/
stas_hash
/
OpenClaw_Assist
Обзор
Документация
Войти
/
stas_hash
/
OpenClaw_Assist
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
scripts/master-setup.sh
419 строк
16 KB
stas
first_commit
24 июл 2026, 13:22
24 июл 2026, 13:22
66d9a26
Код
Авторство
О чём код?
#!/usr/bin/env bash # master-setup.sh — мастер-установка для воркшопа # Один скрипт настраивает всё: файлы, скилы, крон, память, embeddings. # # Использование: # bash master-setup.sh [--dry-run] [--no-embeddings] [--workspace DIR] [--agent NAME] # # По умолчанию: workspace=~/my-assistant, agent=my-assistant. # Требования: openclaw, ollama (опционально, для embeddings). set -euo pipefail # =============== ARGUMENTS =============== WORKSPACE="${WORKSPACE:-$HOME/my-assistant}" AGENT_NAME="${AGENT_NAME:-my-assistant}" DRY_RUN=false NO_EMBEDDINGS=false for arg in "$@"; do case "$arg" in --dry-run) DRY_RUN=true ;; --no-embeddings) NO_EMBEDDINGS=true ;; --workspace=*) WORKSPACE="${arg#--workspace=}" ;; --agent=*) AGENT_NAME="${arg#--agent=}" ;; --help|-h) echo "Usage: bash master-setup.sh [--dry-run] [--no-embeddings] [--workspace DIR] [--agent NAME]" exit 0 ;; esac done # =============== HELPERS =============== run() { if [ "$DRY_RUN" = true ]; then echo " [DRY-RUN] $*" else eval "$@" fi } section() { echo "" echo "═══════════════════════════════════════════════════════" echo "▸ $*" echo "═══════════════════════════════════════════════════════" } # =============== PRECHECK =============== section "0/7 Precheck" if ! command -v openclaw &>/dev/null; then echo "❌ openclaw не установлен. Установите: npm install -g openclaw@latest" exit 1 fi OPENCLAW_VERSION=$(openclaw --version 2>&1 | awk '{print $2}') echo "✅ OpenClaw $OPENCLAW_VERSION" # Проверяем что агент зарегистрирован; если нет — создаём (идемпотентно). if openclaw agents list --json 2>/dev/null | grep -q "\"$AGENT_NAME\""; then echo "✅ Agent '$AGENT_NAME' уже зарегистрирован" else echo "→ Регистрируем агента '$AGENT_NAME'..." run "openclaw agents add $AGENT_NAME --workspace $WORKSPACE --non-interactive" fi if [ "$NO_EMBEDDINGS" = false ]; then if ! command -v ollama &>/dev/null; then echo "⚠️ Ollama не установлена. Embeddings будут пропущены (--no-embeddings)." NO_EMBEDDINGS=true elif ! curl -sf http://localhost:11434/api/tags &>/dev/null; then echo "⚠️ Ollama не запущена (ollama serve). Embeddings будут пропущены." NO_EMBEDDINGS=true else echo "✅ Ollama запущена" fi fi # =============== WORKSPACE =============== section "1/7 Создание workspace" # mkdir выполняем всегда (даже в dry-run) чтобы последующие heredoc-ы могли писать файлы. # dry-run только подавляет реальные изменения внутри run(). mkdir -p "$WORKSPACE" run "cd $WORKSPACE && git init -q 2>/dev/null || true" # =============== BASE FILES =============== section "2/7 Создание шаблонов" # AGENTS.md cat > "$WORKSPACE/AGENTS.md" <<'EOF' # AGENTS.md - System Prompt Я — персональный AI-ассистент на OpenClaw. ## Протокол 1. Перед ответом — прочитай USER.md и SOUL.md 2. Используй активные скилы когда уместно 3. Логируй важные решения в memory/ 4. Если пользователь дал новую информацию — обнови USER.md ## Поведение - Кратко, по делу, в стиле SOUL.md - Не выдумывай — если не знаешь, скажи - Если задача сложная — сначала план, потом делай EOF # SOUL.md cat > "$WORKSPACE/SOUL.md" <<'EOF' # SOUL.md - Who Am I? - **Name**: Мой ассистент - **Vibe**: спокойный, плотно сфокусированный - **Tone**: кратко, по делу, без воды - **Humor**: уместный IT-юмор - **Default emoji**: 🕶️ ## Как общаюсь - Короткие абзацы, не стена текста - Использую списки и таблицы - Без формальностей, без дисклеймеров ## Чего НЕ делаю - ❌ Не называю себя "AI-ассистент" каждый раз - ❌ Не извиняюсь за то что я AI - ❌ Не даю пустых обещаний - ❌ Не вставляю дисклеймеры EOF # USER.md (пустой шаблон) cat > "$WORKSPACE/USER.md" <<'EOF' # USER.md - About Your Human ## Basics - **Name**: [ваше имя] - **Role**: [роль] - **Timezone**: Europe/Moscow ## Communication - Общаемся на «ты» - Кратко, по делу ## What matters - [заполните] ## What to avoid - [заполните] ## Current projects - [заполните] EOF # MEMORY.md cat > "$WORKSPACE/MEMORY.md" <<'EOF' # Long-Term Memory ## Curated facts - (будет заполняться через `openclaw memory promote`) ## Recent decisions - (по мере использования) EOF echo "✅ AGENTS.md, SOUL.md, USER.md, MEMORY.md" # =============== COMMANDS =============== section "3/7 Inline-команды" mkdir -p "$WORKSPACE/.commands" cat > "$WORKSPACE/.commands/morning.md" <<'EOF' --- trigger: "утро|утренняя|сводка|morning" --- Сделай утреннюю сводку: 1. Что горит (тикеты, PR) 2. Что обещали вчера 3. Что запланировано на сегодня 4. Блокеры и риски 5. Один инсайт из dreaming Формат: короткий список, эмодзи-маркеры. EOF cat > "$WORKSPACE/.commands/context.md" <<'EOF' --- trigger: "контекст|что ты знаешь|/context" --- Кратко: что ты знаешь про пользователя (роль, проекты, привычки, что важно). EOF cat > "$WORKSPACE/.commands/standup.md" <<'EOF' --- trigger: "standup|стендап" --- Stand-up draft: что делал вчера, что планирую сегодня, блокеры. 3 строки. EOF echo "✅ .commands/morning.md, context.md, standup.md" # =============== SKILLS =============== section "4/7 Базовые скилы" mkdir -p "$WORKSPACE/skills/jira-quick" cat > "$WORKSPACE/skills/jira-quick/SKILL.md" <<'EOF' --- name: jira-quick description: Сводка по Jira-тикету в 3 строки (статус, assignee, блокеры). emoji: 🎫 --- # Jira Quick Когда пользователь ссылается на тикет (формат XXX-NNN): 1. Извлеки ID 2. Найди: title, status, assignee, linked tickets 3. Кратко: что нужно делать EOF mkdir -p "$WORKSPACE/skills/github-pr-summary" cat > "$WORKSPACE/skills/github-pr-summary/SKILL.md" <<'EOF' --- name: github-pr-summary description: Summary GitHub PR (что меняется, риски, нужно ли ревью). emoji: 🔍 --- # GitHub PR Summary Когда даёшь ссылку/номер PR: 1. Что меняется (1-2 предложения) 2. Риски (low/medium/high) 3. Стоит ли ревьюить сейчас EOF mkdir -p "$WORKSPACE/skills/vector-search" cat > "$WORKSPACE/skills/vector-search/SKILL.md" <<'EOF' --- name: vector-search description: Поиск по памяти по смыслу (не по словам). emoji: 🔎 --- # Vector Search Когда пользователь ищет "тот баг", "обсуждение про X", "помнишь мы говорили про Y": 1. Используй `openclaw memory search` с формулировкой пользователя 2. Верни top-3 результата со скорами 3. Краткое summary что нашлось EOF mkdir -p "$WORKSPACE/skills/morning-summary" cat > "$WORKSPACE/skills/morning-summary/SKILL.md" <<'EOF' --- name: morning-summary description: Утренняя сводка: что горит, что обещали вчера, блокеры. emoji: 🌅 --- # Morning Summary Утренняя сводка. Используй 5 секций: 1. Что горит (тикеты в работе, PR без ревью) 2. Что обещали вчера (memory/YYYY-MM-DD.md) 3. Что запланировано (USER.md контекст) 4. Блокеры и риски 5. Один инсайт (если был dreaming) EOF mkdir -p "$WORKSPACE/skills/draft-reply" cat > "$WORKSPACE/skills/draft-reply/SKILL.md" <<'EOF' --- name: draft-reply description: Draft для email/Slack в стиле пользователя. emoji: ✏️ --- # Draft Reply Когда пользователь просит "напиши ответ Петe" или "draft для Slack": 1. Прочитай контекст (что обсуждали, USER.md для стиля) 2. Напиши draft в стиле пользователя (кратко, по делу) 3. Не отправляй — покажи пользователю EOF echo "✅ skills: jira-quick, github-pr-summary, vector-search, morning-summary, draft-reply" # =============== MEMORY + CRON =============== section "5/7 Память + Cron" # Плагин memory-core уже включён глобально в OpenClaw 2026.7+. # Дополнительная настройка через plugins.entries.memory-core.config не требуется. echo "✅ memory plugin (включён глобально, конфиг не требуется)" # Cron jobs (--declaration-key обеспечивает идемпотентность при перепрогоне) run "openclaw cron add --name dreaming-cycle --declaration-key 'workshop-$AGENT_NAME-dreaming' --cron '0 3 * * *' --agent $AGENT_NAME --session isolated --message 'Перечитай memory/ за 7 дней. Найди 3-5 паттернов: повторяющиеся темы, забытые обещания, неочевидные связи. Напиши мне в Telegram утром.'" run "openclaw cron add --name morning-summary --declaration-key 'workshop-$AGENT_NAME-morning' --cron '0 9 * * 1-5' --agent $AGENT_NAME --session isolated --message 'Напиши мне в Telegram утреннюю сводку. Используй /morning.'" run "openclaw cron add --name weekly-memory-promote --declaration-key 'workshop-$AGENT_NAME-mempromote' --cron '0 22 * * 0' --agent $AGENT_NAME --session isolated --message 'Запусти openclaw memory promote --limit 5 --apply.'" run "openclaw cron add --name vector-index-rebuild --declaration-key 'workshop-$AGENT_NAME-vectoridx' --cron '0 4 * * *' --agent $AGENT_NAME --session isolated --message 'Запусти openclaw memory index --force.'" echo "✅ 4 cron-jobs (с declaration-key для идемпотентности)" # =============== VECTOR STORAGE (sqlite-vec) =============== section "6/7 Vector storage (sqlite-vec)" # В OpenClaw 2026.7+ memory-core хранит embeddings локально в sqlite-vec # (таблица memory_index_chunks_vec в openclaw-agent.sqlite). # Qdrant не используется — внешняя векторная БД не нужна. echo "✅ Векторное хранилище — встроенный sqlite-vec (локально, в openclaw-agent.sqlite)" echo " Размерность: 768 (nomic-embed-text)" echo " Никаких внешних сервисов не требуется." # =============== EMBEDDINGS (OLLAMA) =============== section "7/7 Embeddings через Ollama" # OpenAI плагин жёстко запрашивает модель "text-embedding-3-small". # Если OpenAI ключа нет — переключаем на локальный Ollama: # 1. Скачиваем nomic-embed-text # 2. Создаём alias text-embedding-3-small → nomic-embed-text (нужен потому что OpenAI плагин хардкодит имя) # 3. Перенаправляем OpenAI provider в ~/.openclaw/openclaw.json на http://localhost:11434/v1 # 4. Включаем active-memory плагин (он автоматически инжектит релевантную память в промпт) if [ "$NO_EMBEDDINGS" = true ]; then echo "⏭️ Пропускаем Ollama embeddings (--no-embeddings)." else echo "→ Скачиваем nomic-embed-text (274 MB)..." run "ollama pull nomic-embed-text" echo "→ Создаём alias text-embedding-3-small → nomic-embed-text..." if ! ollama list 2>/dev/null | grep -q "text-embedding-3-small"; then run "ollama cp nomic-embed-text text-embedding-3-small" else echo " ↳ alias уже существует" fi echo "→ Перенаправляем OpenAI provider на Ollama (через openclaw.json)..." if [ "$DRY_RUN" = false ]; then python3 - <<'PYEOF' import json, os cfg_path = os.path.expanduser('~/.openclaw/openclaw.json') with open(cfg_path) as f: d = json.load(f) prov = d.setdefault('models', {}).setdefault('providers', {}) oai = prov.setdefault('openai', {}) oai['baseUrl'] = 'http://localhost:11434/v1' oai['apiKey'] = 'ollama' if not any(m.get('id') == 'nomic-embed-text' for m in oai.get('models', [])): oai.setdefault('models', []).append({ "id": "nomic-embed-text", "name": "Nomic Embed Text (Ollama)", "api": "openai-completions", "baseUrl": "http://localhost:11434/v1", "input": ["text"] }) with open(cfg_path, 'w') as f: json.dump(d, f, indent=2) print('✓ OpenAI provider перенаправлен на Ollama') PYEOF else echo " [DRY-RUN] python3 (обновляет ~/.openclaw/openclaw.json)" fi echo "→ Включаем active-memory плагин..." run "openclaw config set plugins.entries.active-memory.enabled true" fi # =============== AUTH PROFILES (для нового агента) =============== section "Auth-профили (для нового агента)" # Новый агент создаётся без auth-профилей, и CLI у него падает с # "No API key found for provider openai" ещё до того как можно что-то сделать. # Копируем auth_profile_store/auth_profile_state от main. if [ "$DRY_RUN" = false ] && [ -f "$HOME/.openclaw/agents/main/agent/openclaw-agent.sqlite" ]; then AGENT_DB="$HOME/.openclaw/agents/$AGENT_NAME/agent/openclaw-agent.sqlite" if [ -f "$AGENT_DB" ]; then echo "→ Копируем auth-профили от main к $AGENT_NAME..." AGENT_NAME="$AGENT_NAME" python3 - <<'PYEOF' import sqlite3, os home = os.environ['HOME'] agent_name = os.environ['AGENT_NAME'] main_db = f'{home}/.openclaw/agents/main/agent/openclaw-agent.sqlite' dev_db = f'{home}/.openclaw/agents/{agent_name}/agent/openclaw-agent.sqlite' src = sqlite3.connect(main_db); dst = sqlite3.connect(dev_db) for t in ['auth_profile_store', 'auth_profile_state']: try: s = src.cursor() rows = s.execute(f'SELECT * FROM {t}').fetchall() cols = [d[0] for d in s.description] ph = ','.join(['?']*len(cols)) dst.cursor().execute(f'DELETE FROM {t}') dst.cursor().executemany(f'INSERT INTO {t} ({",".join(cols)}) VALUES ({ph})', rows) dst.commit() print(f' ✓ {t}: {len(rows)} строк') except Exception as e: print(f' ✗ {t}: {e}') src.close(); dst.close() PYEOF else echo "⚠️ agent DB не найдена: $AGENT_DB — пропускаем копирование auth" fi fi # =============== RESTART GATEWAY =============== section "Финал" run "openclaw gateway restart" echo "" echo "✨ Мастер-установка завершена!" echo "" echo "Workspace: $WORKSPACE" echo "Agent: $AGENT_NAME" echo "" echo "Дальше:" echo " 1. Откройте $WORKSPACE/USER.md и заполните 5 секций" echo " 2. Напишите боту в Telegram: 'Привет'" echo " 3. Попробуйте команду: 'Что ты умеешь?'" echo " 4. Проверьте память: openclaw memory search 'тест' --agent $AGENT_NAME" echo "" echo "🕶️ Ваш ассистент готов."