One-command persistent memory for Clawdbot. Prevents context amnesia during compaction with: - Two-layer memory: Markdown source of truth + SQLite vector search - Pre-compaction flush to save context before it's lost - Semantic search across all memory files - Daily logs, research intel, and project tracking templates - Interactive installer with dry-run and uninstall support
763 lines
23 KiB
Bash
Executable File
763 lines
23 KiB
Bash
Executable File
<![CDATA[#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
# ============================================================================
|
||
# Clawdbot Memory System — One-Command Installer
|
||
# https://github.com/BusyBee3333/clawdbot-memory-system
|
||
#
|
||
# Usage:
|
||
# bash install.sh # Interactive install
|
||
# bash install.sh --dry-run # Preview changes without applying
|
||
# bash install.sh --uninstall # Remove memory system config
|
||
# ============================================================================
|
||
|
||
VERSION="1.0.0"
|
||
|
||
# --- Colors & Formatting ---
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
MAGENTA='\033[0;35m'
|
||
CYAN='\033[0;36m'
|
||
BOLD='\033[1m'
|
||
DIM='\033[2m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# --- State ---
|
||
DRY_RUN=false
|
||
UNINSTALL=false
|
||
CLAWDBOT_DIR=""
|
||
WORKSPACE_DIR=""
|
||
CONFIG_FILE=""
|
||
AGENTS_FILE=""
|
||
MEMORY_DIR=""
|
||
PROVIDER=""
|
||
API_KEY=""
|
||
CHANGES_MADE=()
|
||
FILES_INDEXED=0
|
||
EXISTING_MEMORY_FILES=0
|
||
|
||
# --- Parse Args ---
|
||
for arg in "$@"; do
|
||
case "$arg" in
|
||
--dry-run) DRY_RUN=true ;;
|
||
--uninstall) UNINSTALL=true ;;
|
||
--help|-h)
|
||
echo "Clawdbot Memory System Installer v${VERSION}"
|
||
echo ""
|
||
echo "Usage:"
|
||
echo " bash install.sh Interactive install"
|
||
echo " bash install.sh --dry-run Preview changes without applying"
|
||
echo " bash install.sh --uninstall Remove memory system config"
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo -e "${RED}Unknown option: $arg${NC}"
|
||
echo "Use --help for usage information."
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# --- Helper Functions ---
|
||
info() { echo -e "${BLUE}ℹ${NC} $1"; }
|
||
success() { echo -e "${GREEN}✅${NC} $1"; }
|
||
warn() { echo -e "${YELLOW}⚠️${NC} $1"; }
|
||
error() { echo -e "${RED}❌${NC} $1"; }
|
||
step() { echo -e "\n${BOLD}${MAGENTA}$1${NC}"; }
|
||
detail() { echo -e " ${DIM}$1${NC}"; }
|
||
dry() { echo -e " ${CYAN}[dry-run]${NC} $1"; }
|
||
|
||
banner() {
|
||
echo ""
|
||
echo -e "${BOLD}${MAGENTA}"
|
||
echo " ╔══════════════════════════════════════════════╗"
|
||
echo " ║ 🧠 Clawdbot Memory System v${VERSION} ║"
|
||
echo " ║ Never lose context to compaction again ║"
|
||
echo " ╚══════════════════════════════════════════════╝"
|
||
echo -e "${NC}"
|
||
}
|
||
|
||
# --- Detect Clawdbot Installation ---
|
||
detect_clawdbot() {
|
||
step "🔍 Detecting Clawdbot installation..."
|
||
|
||
# Check common locations
|
||
for dir in "$HOME/.clawdbot" "$HOME/.openclaw" "$HOME/.moltbot"; do
|
||
if [[ -d "$dir" ]]; then
|
||
CLAWDBOT_DIR="$dir"
|
||
break
|
||
fi
|
||
done
|
||
|
||
if [[ -z "$CLAWDBOT_DIR" ]]; then
|
||
error "Clawdbot installation not found!"
|
||
echo ""
|
||
echo " Looked in:"
|
||
echo " ~/.clawdbot"
|
||
echo " ~/.openclaw"
|
||
echo " ~/.moltbot"
|
||
echo ""
|
||
echo " Make sure Clawdbot is installed first:"
|
||
echo " https://docs.clawd.bot/getting-started"
|
||
exit 1
|
||
fi
|
||
|
||
success "Found Clawdbot at ${BOLD}${CLAWDBOT_DIR}${NC}"
|
||
|
||
# Find config file
|
||
CONFIG_FILE="${CLAWDBOT_DIR}/clawdbot.json"
|
||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||
# Try alternate names
|
||
for name in "openclaw.json" "moltbot.json"; do
|
||
if [[ -f "${CLAWDBOT_DIR}/${name}" ]]; then
|
||
CONFIG_FILE="${CLAWDBOT_DIR}/${name}"
|
||
break
|
||
fi
|
||
done
|
||
fi
|
||
|
||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||
error "Config file not found at ${CONFIG_FILE}"
|
||
echo " Run 'clawdbot doctor' first to initialize your setup."
|
||
exit 1
|
||
fi
|
||
|
||
success "Found config at ${BOLD}${CONFIG_FILE}${NC}"
|
||
|
||
# Find workspace
|
||
WORKSPACE_DIR=$(python3 -c "
|
||
import json, os
|
||
with open('${CONFIG_FILE}') as f:
|
||
cfg = json.load(f)
|
||
ws = cfg.get('agents', {}).get('defaults', {}).get('workspace', '')
|
||
if not ws:
|
||
ws = os.path.expanduser('~') + '/' + os.path.basename('${CLAWDBOT_DIR}') + '/workspace'
|
||
print(os.path.expanduser(ws))
|
||
" 2>/dev/null || echo "${CLAWDBOT_DIR}/workspace")
|
||
|
||
if [[ ! -d "$WORKSPACE_DIR" ]]; then
|
||
warn "Workspace directory not found at ${WORKSPACE_DIR}"
|
||
if $DRY_RUN; then
|
||
dry "Would create workspace directory"
|
||
else
|
||
mkdir -p "$WORKSPACE_DIR"
|
||
success "Created workspace directory"
|
||
fi
|
||
fi
|
||
|
||
success "Workspace: ${BOLD}${WORKSPACE_DIR}${NC}"
|
||
|
||
MEMORY_DIR="${WORKSPACE_DIR}/memory"
|
||
AGENTS_FILE="${WORKSPACE_DIR}/AGENTS.md"
|
||
}
|
||
|
||
# --- Check Dependencies ---
|
||
check_deps() {
|
||
step "🔧 Checking dependencies..."
|
||
|
||
# Check for jq
|
||
if ! command -v jq &>/dev/null; then
|
||
warn "jq is not installed (needed for safe JSON config patching)"
|
||
echo ""
|
||
|
||
if command -v brew &>/dev/null; then
|
||
echo -e " Install with Homebrew? ${DIM}(recommended)${NC}"
|
||
read -rp " [Y/n] " yn
|
||
yn=${yn:-Y}
|
||
if [[ "$yn" =~ ^[Yy] ]]; then
|
||
if $DRY_RUN; then
|
||
dry "Would run: brew install jq"
|
||
else
|
||
echo " Installing jq..."
|
||
brew install jq
|
||
success "jq installed"
|
||
fi
|
||
else
|
||
error "jq is required. Install it manually:"
|
||
echo " brew install jq"
|
||
echo " # or: sudo apt-get install jq"
|
||
echo " # or: https://jqlang.github.io/jq/download/"
|
||
exit 1
|
||
fi
|
||
else
|
||
error "jq is required but not installed."
|
||
echo ""
|
||
echo " Install jq:"
|
||
echo " macOS: brew install jq"
|
||
echo " Ubuntu/Debian: sudo apt-get install jq"
|
||
echo " Other: https://jqlang.github.io/jq/download/"
|
||
exit 1
|
||
fi
|
||
else
|
||
success "jq found: $(jq --version)"
|
||
fi
|
||
|
||
# Check for clawdbot CLI
|
||
if ! command -v clawdbot &>/dev/null; then
|
||
# Try openclaw or moltbot
|
||
if command -v openclaw &>/dev/null; then
|
||
alias clawdbot=openclaw
|
||
success "openclaw CLI found"
|
||
elif command -v moltbot &>/dev/null; then
|
||
alias clawdbot=moltbot
|
||
success "moltbot CLI found"
|
||
else
|
||
warn "clawdbot CLI not found in PATH"
|
||
detail "Index building will be skipped — run manually after install"
|
||
fi
|
||
else
|
||
success "clawdbot CLI found"
|
||
fi
|
||
}
|
||
|
||
# --- Check Existing Memory Files ---
|
||
check_existing() {
|
||
step "📂 Checking existing memory files..."
|
||
|
||
if [[ -d "$MEMORY_DIR" ]]; then
|
||
EXISTING_MEMORY_FILES=$(find "$MEMORY_DIR" -name "*.md" -type f 2>/dev/null | wc -l | tr -d ' ')
|
||
if [[ "$EXISTING_MEMORY_FILES" -gt 0 ]]; then
|
||
info "Found ${BOLD}${EXISTING_MEMORY_FILES}${NC} existing memory files in ${MEMORY_DIR}"
|
||
detail "These will be preserved and indexed"
|
||
else
|
||
info "Memory directory exists but is empty"
|
||
fi
|
||
else
|
||
info "No existing memory directory — will create one"
|
||
fi
|
||
|
||
# Check for MEMORY.md
|
||
if [[ -f "${WORKSPACE_DIR}/MEMORY.md" ]]; then
|
||
info "Found existing MEMORY.md — will be included in index"
|
||
fi
|
||
}
|
||
|
||
# --- Create Memory Directory & Templates ---
|
||
setup_memory_dir() {
|
||
step "📝 Setting up memory directory and templates..."
|
||
|
||
if $DRY_RUN; then
|
||
if [[ ! -d "$MEMORY_DIR" ]]; then
|
||
dry "Would create ${MEMORY_DIR}/"
|
||
fi
|
||
dry "Would copy template files to ${MEMORY_DIR}/"
|
||
return
|
||
fi
|
||
|
||
# Create memory directory
|
||
if [[ ! -d "$MEMORY_DIR" ]]; then
|
||
mkdir -p "$MEMORY_DIR"
|
||
success "Created ${MEMORY_DIR}/"
|
||
CHANGES_MADE+=("Created memory/ directory")
|
||
else
|
||
info "Memory directory already exists"
|
||
fi
|
||
|
||
# Copy templates (don't overwrite existing)
|
||
local script_dir
|
||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
local templates_dir="${script_dir}/templates"
|
||
|
||
# If running from curl, download templates
|
||
if [[ ! -d "$templates_dir" ]]; then
|
||
local base_url="https://raw.githubusercontent.com/BusyBee3333/clawdbot-memory-system/main/templates"
|
||
templates_dir=$(mktemp -d)
|
||
|
||
for tmpl in TEMPLATE-daily.md TEMPLATE-research-intel.md TEMPLATE-project-tracking.md; do
|
||
curl -sL "${base_url}/${tmpl}" -o "${templates_dir}/${tmpl}" 2>/dev/null || true
|
||
done
|
||
fi
|
||
|
||
# Copy each template if it doesn't exist
|
||
for tmpl_file in "${templates_dir}"/TEMPLATE-*.md; do
|
||
[[ -f "$tmpl_file" ]] || continue
|
||
local basename
|
||
basename=$(basename "$tmpl_file")
|
||
if [[ ! -f "${MEMORY_DIR}/${basename}" ]]; then
|
||
cp "$tmpl_file" "${MEMORY_DIR}/${basename}"
|
||
success "Added template: ${basename}"
|
||
CHANGES_MADE+=("Added ${basename}")
|
||
else
|
||
detail "Template already exists: ${basename}"
|
||
fi
|
||
done
|
||
|
||
# Create today's daily log if none exists
|
||
local today
|
||
today=$(date +%Y-%m-%d)
|
||
if [[ ! -f "${MEMORY_DIR}/${today}.md" ]]; then
|
||
cat > "${MEMORY_DIR}/${today}.md" << 'DAILY'
|
||
# Daily Log — $(date +%Y-%m-%d)
|
||
|
||
## What We Worked On
|
||
- Set up Clawdbot Memory System 🧠
|
||
|
||
## Decisions Made
|
||
- Installed persistent memory to prevent context loss during compaction
|
||
|
||
## Next Steps
|
||
- Use the memory system naturally — agent will write daily logs
|
||
- Check `memory/` directory for accumulated context over time
|
||
|
||
## Open Questions / Blockers
|
||
-
|
||
|
||
## Notable Context
|
||
Memory system installed and indexed. Agent should now persist important context
|
||
across sessions automatically.
|
||
DAILY
|
||
# Fix the date in the file
|
||
sed -i.bak "s/\$(date +%Y-%m-%d)/${today}/g" "${MEMORY_DIR}/${today}.md" 2>/dev/null && rm -f "${MEMORY_DIR}/${today}.md.bak"
|
||
success "Created today's daily log: ${today}.md"
|
||
CHANGES_MADE+=("Created daily log ${today}.md")
|
||
fi
|
||
}
|
||
|
||
# --- Choose Embedding Provider ---
|
||
choose_provider() {
|
||
step "🤖 Choose your embedding provider..."
|
||
|
||
echo ""
|
||
echo -e " ${BOLD}1)${NC} ${GREEN}OpenAI${NC} ${DIM}(recommended — fast, cheap ~\$0.02/M tokens)${NC}"
|
||
echo -e " ${BOLD}2)${NC} ${BLUE}Gemini${NC} ${DIM}(free tier available)${NC}"
|
||
echo -e " ${BOLD}3)${NC} ${YELLOW}Local${NC} ${DIM}(free, offline, slower first run)${NC}"
|
||
echo ""
|
||
|
||
read -rp " Choose [1/2/3] (default: 1): " choice
|
||
choice=${choice:-1}
|
||
|
||
case "$choice" in
|
||
1) PROVIDER="openai" ;;
|
||
2) PROVIDER="gemini" ;;
|
||
3) PROVIDER="local" ;;
|
||
*)
|
||
warn "Invalid choice, defaulting to OpenAI"
|
||
PROVIDER="openai"
|
||
;;
|
||
esac
|
||
|
||
success "Selected: ${BOLD}${PROVIDER}${NC}"
|
||
|
||
# Prompt for API key if needed
|
||
if [[ "$PROVIDER" == "openai" ]]; then
|
||
if [[ -n "${OPENAI_API_KEY:-}" ]]; then
|
||
info "Found OPENAI_API_KEY in environment"
|
||
else
|
||
echo ""
|
||
echo -e " ${DIM}OpenAI API key is needed for embeddings.${NC}"
|
||
echo -e " ${DIM}Get one at: https://platform.openai.com/api-keys${NC}"
|
||
echo -e " ${DIM}(Press Enter to skip — you can set it later as OPENAI_API_KEY)${NC}"
|
||
echo ""
|
||
read -rsp " OpenAI API Key: " API_KEY
|
||
echo ""
|
||
if [[ -n "$API_KEY" ]]; then
|
||
success "API key provided"
|
||
else
|
||
warn "No API key provided — set OPENAI_API_KEY env var before using memory search"
|
||
fi
|
||
fi
|
||
elif [[ "$PROVIDER" == "gemini" ]]; then
|
||
if [[ -n "${GEMINI_API_KEY:-}" ]]; then
|
||
info "Found GEMINI_API_KEY in environment"
|
||
else
|
||
echo ""
|
||
echo -e " ${DIM}Gemini API key is needed for embeddings.${NC}"
|
||
echo -e " ${DIM}Get one at: https://aistudio.google.com/apikey${NC}"
|
||
echo -e " ${DIM}(Press Enter to skip — you can set it later as GEMINI_API_KEY)${NC}"
|
||
echo ""
|
||
read -rsp " Gemini API Key: " API_KEY
|
||
echo ""
|
||
if [[ -n "$API_KEY" ]]; then
|
||
success "API key provided"
|
||
else
|
||
warn "No API key provided — set GEMINI_API_KEY env var before using memory search"
|
||
fi
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# --- Patch clawdbot.json ---
|
||
patch_config() {
|
||
step "⚙️ Patching clawdbot.json..."
|
||
|
||
# Check if memorySearch already configured
|
||
local existing_provider
|
||
existing_provider=$(jq -r '.agents.defaults.memorySearch.provider // empty' "$CONFIG_FILE" 2>/dev/null || true)
|
||
|
||
if [[ -n "$existing_provider" ]]; then
|
||
info "memorySearch already configured (provider: ${existing_provider})"
|
||
echo ""
|
||
read -rp " Overwrite with new provider ($PROVIDER)? [y/N] " yn
|
||
yn=${yn:-N}
|
||
if [[ ! "$yn" =~ ^[Yy] ]]; then
|
||
info "Keeping existing config"
|
||
return
|
||
fi
|
||
fi
|
||
|
||
if $DRY_RUN; then
|
||
dry "Would back up ${CONFIG_FILE} → ${CONFIG_FILE}.pre-memory-backup"
|
||
dry "Would add memorySearch config (provider: ${PROVIDER})"
|
||
if [[ -n "$API_KEY" ]]; then
|
||
dry "Would add API key to config"
|
||
fi
|
||
return
|
||
fi
|
||
|
||
# Back up config
|
||
cp "$CONFIG_FILE" "${CONFIG_FILE}.pre-memory-backup"
|
||
success "Backed up config → ${CONFIG_FILE}.pre-memory-backup"
|
||
|
||
# Build the memorySearch config based on provider
|
||
local memory_config
|
||
case "$PROVIDER" in
|
||
openai)
|
||
memory_config='{"provider":"openai","model":"text-embedding-3-small"}'
|
||
if [[ -n "$API_KEY" ]]; then
|
||
memory_config=$(echo "$memory_config" | jq --arg key "$API_KEY" '. + {remote: {apiKey: $key}}')
|
||
fi
|
||
;;
|
||
gemini)
|
||
memory_config='{"provider":"gemini","model":"gemini-embedding-001"}'
|
||
if [[ -n "$API_KEY" ]]; then
|
||
memory_config=$(echo "$memory_config" | jq --arg key "$API_KEY" '. + {remote: {apiKey: $key}}')
|
||
fi
|
||
;;
|
||
local)
|
||
memory_config='{"provider":"local"}'
|
||
;;
|
||
esac
|
||
|
||
# Merge into config using jq (safe, non-destructive)
|
||
local tmp_file
|
||
tmp_file=$(mktemp)
|
||
|
||
jq --argjson ms "$memory_config" '
|
||
.agents.defaults.memorySearch = (
|
||
(.agents.defaults.memorySearch // {}) * $ms
|
||
)
|
||
' "$CONFIG_FILE" > "$tmp_file"
|
||
|
||
# Validate the result is valid JSON
|
||
if jq empty "$tmp_file" 2>/dev/null; then
|
||
mv "$tmp_file" "$CONFIG_FILE"
|
||
success "Added memorySearch config (provider: ${PROVIDER})"
|
||
CHANGES_MADE+=("Patched clawdbot.json with memorySearch (${PROVIDER})")
|
||
else
|
||
rm -f "$tmp_file"
|
||
error "Failed to patch config — restoring backup"
|
||
cp "${CONFIG_FILE}.pre-memory-backup" "$CONFIG_FILE"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# --- Patch AGENTS.md ---
|
||
patch_agents() {
|
||
step "📋 Updating AGENTS.md with memory instructions..."
|
||
|
||
# Check if already patched
|
||
if [[ -f "$AGENTS_FILE" ]] && grep -q "memory_search\|Daily memory log\|Pre-compaction flush" "$AGENTS_FILE" 2>/dev/null; then
|
||
info "AGENTS.md already contains memory instructions"
|
||
return
|
||
fi
|
||
|
||
if $DRY_RUN; then
|
||
dry "Would append memory instructions to ${AGENTS_FILE}"
|
||
return
|
||
fi
|
||
|
||
# Get the patch content
|
||
local script_dir
|
||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
local patch_file="${script_dir}/config/agents-memory-patch.md"
|
||
local patch_content
|
||
|
||
if [[ -f "$patch_file" ]]; then
|
||
patch_content=$(cat "$patch_file")
|
||
else
|
||
# Download if running from curl
|
||
patch_content=$(curl -sL "https://raw.githubusercontent.com/BusyBee3333/clawdbot-memory-system/main/config/agents-memory-patch.md" 2>/dev/null || true)
|
||
fi
|
||
|
||
if [[ -z "$patch_content" ]]; then
|
||
# Fallback: inline the patch
|
||
patch_content='
|
||
## Memory System (auto-added by clawdbot-memory-system installer)
|
||
|
||
### Mandatory Memory Recall
|
||
Before answering ANY question about prior work, decisions, or context from previous sessions:
|
||
1. Use `memory_search` to find relevant memories
|
||
2. Check today'\''s daily log: `memory/YYYY-MM-DD.md`
|
||
3. Check yesterday'\''s log if today'\''s is sparse
|
||
4. Only say "I don'\''t recall" if memory search returns nothing
|
||
|
||
### Daily Memory Log
|
||
- Write to `memory/YYYY-MM-DD.md` throughout the session
|
||
- Log: decisions, preferences, project progress, action items, blockers
|
||
- Be specific — future-you needs exact details, not vague summaries
|
||
|
||
### Pre-Compaction Flush
|
||
When you sense a session is getting long or receive a compaction warning:
|
||
- Write ALL important unsaved context to today'\''s daily log
|
||
- Include: what we were working on, where we left off, any pending decisions
|
||
- This is your safety net against amnesia
|
||
|
||
### Research Intel System
|
||
For ongoing research/monitoring projects:
|
||
- Store in: `memory/{project}-research-intel.md`
|
||
- Current week'\''s detailed intel at TOP
|
||
- Compressed 1-3 sentence summaries of previous weeks at BOTTOM
|
||
- Check for active research intel files on strategic questions
|
||
|
||
### Git Backup
|
||
End of session: `cd ~/.clawdbot/workspace && git add -A && git commit -m "session backup" && git push`
|
||
'
|
||
fi
|
||
|
||
if [[ -f "$AGENTS_FILE" ]]; then
|
||
echo "" >> "$AGENTS_FILE"
|
||
echo "$patch_content" >> "$AGENTS_FILE"
|
||
else
|
||
echo "$patch_content" > "$AGENTS_FILE"
|
||
fi
|
||
|
||
success "Added memory instructions to AGENTS.md"
|
||
CHANGES_MADE+=("Updated AGENTS.md with memory habits")
|
||
}
|
||
|
||
# --- Build Index ---
|
||
build_index() {
|
||
step "🔨 Building memory search index..."
|
||
|
||
if $DRY_RUN; then
|
||
dry "Would run: clawdbot memory index --verbose"
|
||
dry "Would run: clawdbot memory status --deep"
|
||
return
|
||
fi
|
||
|
||
if ! command -v clawdbot &>/dev/null; then
|
||
warn "clawdbot CLI not in PATH — skipping index build"
|
||
detail "Run manually: clawdbot memory index --verbose"
|
||
return
|
||
fi
|
||
|
||
echo ""
|
||
info "Indexing memory files..."
|
||
echo -e "${DIM}"
|
||
|
||
if clawdbot memory index --verbose 2>&1; then
|
||
echo -e "${NC}"
|
||
success "Index built successfully"
|
||
else
|
||
echo -e "${NC}"
|
||
warn "Index build had issues (this may be normal on first run)"
|
||
detail "Check: clawdbot memory status --deep"
|
||
fi
|
||
|
||
echo ""
|
||
info "Verifying installation..."
|
||
echo -e "${DIM}"
|
||
|
||
if clawdbot memory status --deep 2>&1; then
|
||
echo -e "${NC}"
|
||
success "Memory system verified"
|
||
else
|
||
echo -e "${NC}"
|
||
warn "Status check had warnings (embedding provider may need API key)"
|
||
fi
|
||
|
||
# Count indexed files
|
||
FILES_INDEXED=$(find "$MEMORY_DIR" -name "*.md" -type f 2>/dev/null | wc -l | tr -d ' ')
|
||
if [[ -f "${WORKSPACE_DIR}/MEMORY.md" ]]; then
|
||
FILES_INDEXED=$((FILES_INDEXED + 1))
|
||
fi
|
||
}
|
||
|
||
# --- Print Summary ---
|
||
print_summary() {
|
||
echo ""
|
||
echo -e "${BOLD}${GREEN}"
|
||
echo " ╔══════════════════════════════════════════════╗"
|
||
echo " ║ 🎉 Installation Complete! ║"
|
||
echo " ╚══════════════════════════════════════════════╝"
|
||
echo -e "${NC}"
|
||
|
||
if [[ ${#CHANGES_MADE[@]} -gt 0 ]]; then
|
||
echo -e " ${BOLD}Changes made:${NC}"
|
||
for change in "${CHANGES_MADE[@]}"; do
|
||
echo -e " ${GREEN}✓${NC} ${change}"
|
||
done
|
||
echo ""
|
||
fi
|
||
|
||
if [[ "$EXISTING_MEMORY_FILES" -gt 0 ]]; then
|
||
echo -e " ${BOLD}Migration:${NC}"
|
||
echo -e " 📁 ${EXISTING_MEMORY_FILES} existing memory files preserved and indexed"
|
||
echo ""
|
||
fi
|
||
|
||
echo -e " ${BOLD}Index:${NC}"
|
||
echo -e " 📊 ${FILES_INDEXED} memory files indexed"
|
||
echo -e " 🤖 Provider: ${PROVIDER}"
|
||
echo ""
|
||
|
||
echo -e " ${BOLD}${CYAN}Next steps:${NC}"
|
||
echo ""
|
||
echo -e " ${BOLD}1.${NC} Restart the gateway to apply config changes:"
|
||
echo -e " ${DIM}clawdbot gateway restart${NC}"
|
||
echo ""
|
||
echo -e " ${BOLD}2.${NC} Start chatting! Your agent will now:"
|
||
echo -e " • Write daily logs to memory/${DIM}YYYY-MM-DD${NC}.md"
|
||
echo -e " • Search memories before answering about prior work"
|
||
echo -e " • Flush context before compaction"
|
||
echo ""
|
||
echo -e " ${BOLD}3.${NC} Verify anytime with:"
|
||
echo -e " ${DIM}clawdbot memory status --deep${NC}"
|
||
echo ""
|
||
|
||
if [[ -n "$API_KEY" ]]; then
|
||
echo -e " ${YELLOW}⚠️ Your API key was saved to clawdbot.json.${NC}"
|
||
echo -e " ${DIM} Alternatively, set it as an env var and remove from config.${NC}"
|
||
echo ""
|
||
fi
|
||
|
||
echo -e " ${DIM}Problems? See: https://github.com/BusyBee3333/clawdbot-memory-system#troubleshooting${NC}"
|
||
echo ""
|
||
}
|
||
|
||
# --- Print Dry Run Summary ---
|
||
print_dry_summary() {
|
||
echo ""
|
||
echo -e "${BOLD}${CYAN}"
|
||
echo " ╔══════════════════════════════════════════════╗"
|
||
echo " ║ 📋 Dry Run Summary ║"
|
||
echo " ╚══════════════════════════════════════════════╝"
|
||
echo -e "${NC}"
|
||
echo ""
|
||
echo -e " No changes were made. Run without ${CYAN}--dry-run${NC} to apply."
|
||
echo ""
|
||
}
|
||
|
||
# --- Uninstall ---
|
||
do_uninstall() {
|
||
banner
|
||
step "🗑️ Uninstalling Clawdbot Memory System..."
|
||
|
||
detect_clawdbot
|
||
|
||
echo ""
|
||
warn "This will:"
|
||
echo " • Remove memorySearch config from clawdbot.json"
|
||
echo " • Remove memory instructions from AGENTS.md"
|
||
echo ""
|
||
echo -e " ${BOLD}This will NOT delete your memory/ files.${NC}"
|
||
echo " Your memories are safe — only the config is removed."
|
||
echo ""
|
||
read -rp " Continue? [y/N] " yn
|
||
yn=${yn:-N}
|
||
if [[ ! "$yn" =~ ^[Yy] ]]; then
|
||
info "Cancelled"
|
||
exit 0
|
||
fi
|
||
|
||
# Remove memorySearch from config
|
||
if [[ -f "$CONFIG_FILE" ]] && jq -e '.agents.defaults.memorySearch' "$CONFIG_FILE" &>/dev/null; then
|
||
cp "$CONFIG_FILE" "${CONFIG_FILE}.pre-uninstall-backup"
|
||
local tmp_file
|
||
tmp_file=$(mktemp)
|
||
jq 'del(.agents.defaults.memorySearch)' "$CONFIG_FILE" > "$tmp_file"
|
||
if jq empty "$tmp_file" 2>/dev/null; then
|
||
mv "$tmp_file" "$CONFIG_FILE"
|
||
success "Removed memorySearch from config"
|
||
else
|
||
rm -f "$tmp_file"
|
||
error "Failed to patch config"
|
||
fi
|
||
else
|
||
info "No memorySearch config found"
|
||
fi
|
||
|
||
# Remove memory instructions from AGENTS.md
|
||
if [[ -f "$AGENTS_FILE" ]]; then
|
||
if grep -q "Memory System (auto-added by clawdbot-memory-system installer)" "$AGENTS_FILE" 2>/dev/null; then
|
||
cp "$AGENTS_FILE" "${AGENTS_FILE}.pre-uninstall-backup"
|
||
# Remove everything from the memory system header to the end of that section
|
||
sed -i.bak '/## Memory System (auto-added by clawdbot-memory-system installer)/,$ { /## Memory System (auto-added by clawdbot-memory-system installer)/d; /^## [^M]/!d; }' "$AGENTS_FILE" 2>/dev/null
|
||
# Simpler approach: use python to remove the section
|
||
python3 -c "
|
||
import re
|
||
with open('${AGENTS_FILE}') as f:
|
||
content = f.read()
|
||
# Remove the auto-added section
|
||
pattern = r'\n*## Memory System \(auto-added by clawdbot-memory-system installer\).*'
|
||
content = re.sub(pattern, '', content, flags=re.DOTALL)
|
||
with open('${AGENTS_FILE}', 'w') as f:
|
||
f.write(content.rstrip() + '\n')
|
||
" 2>/dev/null || true
|
||
rm -f "${AGENTS_FILE}.bak"
|
||
success "Removed memory instructions from AGENTS.md"
|
||
else
|
||
info "No auto-added memory instructions found in AGENTS.md"
|
||
fi
|
||
fi
|
||
|
||
echo ""
|
||
success "Uninstall complete"
|
||
echo ""
|
||
echo -e " ${DIM}Your memory/ files were preserved.${NC}"
|
||
echo -e " ${DIM}Config backups saved as .pre-uninstall-backup files.${NC}"
|
||
echo -e " ${DIM}Run 'clawdbot gateway restart' to apply changes.${NC}"
|
||
echo ""
|
||
exit 0
|
||
}
|
||
|
||
# ============================================================================
|
||
# Main Flow
|
||
# ============================================================================
|
||
|
||
# Handle uninstall
|
||
if $UNINSTALL; then
|
||
do_uninstall
|
||
fi
|
||
|
||
# Banner
|
||
banner
|
||
|
||
if $DRY_RUN; then
|
||
echo -e " ${CYAN}${BOLD}Running in dry-run mode — no changes will be made${NC}"
|
||
echo ""
|
||
fi
|
||
|
||
# Step 1: Detect Clawdbot
|
||
detect_clawdbot
|
||
|
||
# Step 2: Check dependencies
|
||
check_deps
|
||
|
||
# Step 3: Check existing files
|
||
check_existing
|
||
|
||
# Step 4: Choose provider
|
||
choose_provider
|
||
|
||
# Step 5: Set up memory directory
|
||
setup_memory_dir
|
||
|
||
# Step 6: Patch clawdbot.json
|
||
patch_config
|
||
|
||
# Step 7: Patch AGENTS.md
|
||
patch_agents
|
||
|
||
# Step 8: Build index
|
||
build_index
|
||
|
||
# Step 9: Summary
|
||
if $DRY_RUN; then
|
||
print_dry_summary
|
||
else
|
||
print_summary
|
||
fi
|
||
]]> |