Предлагаю создать систему памяти для Gemini CLI с использованием Git hooks и локальной базы данных. Вот полное решение:
Структура системы памяти
1. Основной скрипт установки
#!/bin/bash
# install_memory_system.sh
# Создание директории для системы памяти
mkdir -p ~/.gemini-memory
mkdir -p ~/.gemini-memory/projects
mkdir -p ~/.gemini-memory/templates
# Установка зависимостей
echo "Установка зависимостей..."
sudo apt-get update
sudo apt-get install -y python3-pip sqlite3 jq
pip3 install --user gitpython watchdog pyyaml
# Копирование скриптов
cp gemini_memory.py ~/.gemini-memory/
cp memory_hook.sh ~/.gemini-memory/
chmod +x ~/.gemini-memory/*.sh
chmod +x ~/.gemini-memory/*.py
echo "Система памяти установлена!"
2. Основной Python модуль системы памяти
#!/usr/bin/env python3
# ~/.gemini-memory/gemini_memory.py
import os
import json
import sqlite3
import hashlib
import datetime
from pathlib import Path
import git
import yaml
from typing import Dict, List, Optional
class GeminiMemory:
def __init__(self, project_path: str = None):
self.base_dir = Path.home() / '.gemini-memory'
self.base_dir.mkdir(exist_ok=True)
if project_path:
self.project_path = Path(project_path).resolve()
self.project_id = self._get_project_id()
self.db_path = self.base_dir / 'projects' / f'{self.project_id}.db'
self._init_database()
def _get_project_id(self) -> str:
"""Генерирует уникальный ID для проекта"""
return hashlib.md5(str(self.project_path).encode()).hexdigest()[:12]
def _init_database(self):
"""Инициализирует базу данных для проекта"""
self.db_path.parent.mkdir(exist_ok=True)
conn = sqlite3.connect(str(self.db_path))
cursor = conn.cursor()
# Таблица изменений кода
cursor.execute('''
CREATE TABLE IF NOT EXISTS code_changes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
file_path TEXT,
change_type TEXT,
diff TEXT,
commit_hash TEXT,
branch TEXT,
summary TEXT
)
''')
# Таблица взаимодействий с AI
cursor.execute('''
CREATE TABLE IF NOT EXISTS ai_interactions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
prompt TEXT,
response TEXT,
context TEXT,
tags TEXT,
token_count INTEGER
)
''')
# Таблица задач и решений
cursor.execute('''
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
task_description TEXT,
status TEXT,
solution TEXT,
files_affected TEXT,
complexity INTEGER
)
''')
# Таблица архитектурных решений
cursor.execute('''
CREATE TABLE IF NOT EXISTS architecture_decisions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
decision TEXT,
reasoning TEXT,
alternatives TEXT,
impact TEXT
)
''')
conn.commit()
conn.close()
def record_change(self, file_path: str, change_type: str, diff: str, summary: str = None):
"""Записывает изменение в коде"""
conn = sqlite3.connect(str(self.db_path))
cursor = conn.cursor()
try:
repo = git.Repo(self.project_path)
commit_hash = repo.head.commit.hexsha if repo.head.is_valid() else None
branch = repo.active_branch.name if not repo.head.is_detached else 'detached'
except:
commit_hash = None
branch = 'unknown'
cursor.execute('''
INSERT INTO code_changes (file_path, change_type, diff, commit_hash, branch, summary)
VALUES (?, ?, ?, ?, ?, ?)
''', (file_path, change_type, diff, commit_hash, branch, summary))
conn.commit()
conn.close()
def record_ai_interaction(self, prompt: str, response: str, context: str = None, tags: List[str] = None):
"""Записывает взаимодействие с AI"""
conn = sqlite3.connect(str(self.db_path))
cursor = conn.cursor()
tags_str = json.dumps(tags) if tags else '[]'
token_count = len(prompt.split()) + len(response.split())
cursor.execute('''
INSERT INTO ai_interactions (prompt, response, context, tags, token_count)
VALUES (?, ?, ?, ?, ?)
''', (prompt, response, context, tags_str, token_count))
conn.commit()
conn.close()
def get_project_context(self, limit: int = 10) -> Dict:
"""Получает контекст проекта для AI"""
conn = sqlite3.connect(str(self.db_path))
cursor = conn.cursor()
# Последние изменения
cursor.execute('''
SELECT * FROM code_changes
ORDER BY timestamp DESC
LIMIT ?
''', (limit,))
recent_changes = cursor.fetchall()
# Последние взаимодействия
cursor.execute('''
SELECT * FROM ai_interactions
ORDER BY timestamp DESC
LIMIT ?
''', (limit,))
recent_interactions = cursor.fetchall()
# Активные задачи
cursor.execute('''
SELECT * FROM tasks
WHERE status != 'completed'
ORDER BY timestamp DESC
''')
active_tasks = cursor.fetchall()
# Архитектурные решения
cursor.execute('''
SELECT * FROM architecture_decisions
ORDER BY timestamp DESC
LIMIT 5
''')
architecture = cursor.fetchall()
conn.close()
return {
'project_path': str(self.project_path),
'recent_changes': self._format_records(recent_changes, 'code_changes'),
'recent_interactions': self._format_records(recent_interactions, 'ai_interactions'),
'active_tasks': self._format_records(active_tasks, 'tasks'),
'architecture': self._format_records(architecture, 'architecture_decisions')
}
def _format_records(self, records: List, table_name: str) -> List[Dict]:
"""Форматирует записи из БД"""
formatted = []
for record in records:
if table_name == 'code_changes':
formatted.append({
'timestamp': record[1],
'file': record[2],
'type': record[3],
'diff': record[4][:200] + '...' if len(record[4]) > 200 else record[4],
'commit': record[5],
'branch': record[6],
'summary': record[7]
})
elif table_name == 'ai_interactions':
formatted.append({
'timestamp': record[1],
'prompt': record[2][:100] + '...' if len(record[2]) > 100 else record[2],
'response': record[3][:200] + '...' if len(record[3]) > 200 else record[3],
'context': record[4],
'tags': json.loads(record[5]) if record[5] else []
})
elif table_name == 'tasks':
formatted.append({
'timestamp': record[1],
'description': record[2],
'status': record[3],
'solution': record[4],
'files': record[5]
})
elif table_name == 'architecture_decisions':
formatted.append({
'timestamp': record[1],
'decision': record[2],
'reasoning': record[3]
})
return formatted
def generate_summary(self) -> str:
"""Генерирует саммари проекта для AI"""
context = self.get_project_context()
summary = f"""
# Контекст проекта: {context['project_path']}
## Последние изменения в коде:
"""
for change in context['recent_changes'][:5]:
summary += f"- [{change['timestamp']}] {change['file']}: {change['type']}\n"
if change['summary']:
summary += f" Описание: {change['summary']}\n"
summary += "\n## Активные задачи:\n"
for task in context['active_tasks'][:3]:
summary += f"- [{task['status']}] {task['description']}\n"
summary += "\n## Архитектурные решения:\n"
for decision in context['architecture'][:3]:
summary += f"- {decision['decision']}\n"
summary += f" Обоснование: {decision['reasoning']}\n"
return summary
3. Git Hook для отслеживания изменений
#!/bin/bash
# ~/.gemini-memory/git_hook.sh
PROJECT_PATH=$(git rev-parse --show-toplevel)
MEMORY_SCRIPT=~/.gemini-memory/gemini_memory.py
# Получаем информацию о коммите
COMMIT_MSG=$(git log -1 --pretty=%B)
CHANGED_FILES=$(git diff-tree --no-commit-id --name-only -r HEAD)
# Записываем изменения в память
python3 -c "
import sys
sys.path.insert(0, '$HOME/.gemini-memory')
from gemini_memory import GeminiMemory
memory = GeminiMemory('$PROJECT_PATH')
commit_msg = '''$COMMIT_MSG'''
files = '''$CHANGED_FILES'''.split('\n')
for file in files:
if file:
diff = '$(git diff HEAD~1 HEAD -- {} 2>/dev/null | head -100)'
memory.record_change(file, 'commit', diff, commit_msg)
"
4. CLI интерфейс для Gemini
#!/usr/bin/env python3
# ~/.gemini-memory/gemini_cli_wrapper.py
import os
import sys
import json
import subprocess
from pathlib import Path
from gemini_memory import GeminiMemory
import argparse
class GeminiCLIWrapper:
def __init__(self):
self.current_project = self._detect_project()
if self.current_project:
self.memory = GeminiMemory(self.current_project)
def _detect_project(self) -> Optional[str]:
"""Определяет текущий проект по git репозиторию"""
try:
result = subprocess.run(
['git', 'rev-parse', '--show-toplevel'],
capture_output=True, text=True
)
if result.returncode == 0:
return result.stdout.strip()
except:
pass
return None
def enhance_prompt(self, original_prompt: str) -> str:
"""Добавляет контекст к промпту"""
if not self.memory:
return original_prompt
context = self.memory.generate_summary()
enhanced = f"""
{context}
---
Текущий запрос: {original_prompt}
Учитывай контекст проекта и предыдущие решения при ответе.
"""
return enhanced
def run_gemini(self, prompt: str, save_interaction: bool = True):
"""Запускает Gemini с улучшенным промптом"""
enhanced_prompt = self.enhance_prompt(prompt)
# Здесь вызов Gemini CLI (адаптируйте под вашу версию)
result = subprocess.run(
['gemini', 'ask', enhanced_prompt],
capture_output=True, text=True
)
response = result.stdout
if save_interaction and self.memory:
self.memory.record_ai_interaction(
prompt=prompt,
response=response,
context=self.current_project
)
return response
def init_project(self):
"""Инициализирует память для проекта"""
if not self.current_project:
print("Не найден git репозиторий")
return
# Установка git hooks
hooks_dir = Path(self.current_project) / '.git' / 'hooks'
post_commit = hooks_dir / 'post-commit'
with open(post_commit, 'w') as f:
f.write('#!/bin/bash\n')
f.write('~/.gemini-memory/git_hook.sh\n')
os.chmod(post_commit, 0o755)
print(f"Память инициализирована для проекта: {self.current_project}")
def main():
parser = argparse.ArgumentParser(description='Gemini CLI с системой памяти')
parser.add_argument('command', choices=['init', 'ask', 'context', 'summary'])
parser.add_argument('prompt', nargs='?', help='Промпт для Gemini')
parser.add_argument('--no-save', action='store_true', help='Не сохранять взаимодействие')
args = parser.parse_args()
wrapper = GeminiCLIWrapper()
if args.command == 'init':
wrapper.init_project()
elif args.command == 'ask':
if not args.prompt:
print("Необходим промпт для команды ask")
sys.exit(1)
response = wrapper.run_gemini(args.prompt, not args.no_save)
print(response)
elif args.command == 'context':
if wrapper.memory:
context = wrapper.memory.get_project_context()
print(json.dumps(context, indent=2, ensure_ascii=False))
elif args.command == 'summary':
if wrapper.memory:
print(wrapper.memory.generate_summary())
if __name__ == '__main__':
main()
5. Bash алиас для удобства
# Добавить в ~/.bashrc или ~/.zshrc
# Алиас для Gemini с памятью
alias gmem='python3 ~/.gemini-memory/gemini_cli_wrapper.py'
# Функция для быстрого запроса
gask() {
python3 ~/.gemini-memory/gemini_cli_wrapper.py ask "$*"
}
# Инициализация памяти в текущем проекте
ginit() {
python3 ~/.gemini-memory/gemini_cli_wrapper.py init
}
# Показать контекст проекта
gcontext() {
python3 ~/.gemini-memory/gemini_cli_wrapper.py context
}
6. Конфигурационный файл
# ~/.gemini-memory/config.yaml
memory:
max_context_items: 20
max_token_count: 4000
auto_summarize: true
projects:
default_tags:
- architecture
- bugfix
- feature
- refactoring
storage:
cleanup_days: 90
backup_enabled: true
backup_path: ~/.gemini-memory/backups
gemini:
model: gemini-pro
temperature: 0.7
max_tokens: 2048
Установка и использование
- Установка системы:
# Клонируйте репозиторий или создайте файлы
chmod +x install_memory_system.sh
./install_memory_system.sh
- Инициализация в проекте:
cd /path/to/your/project
ginit
- Использование:
# Обычный запрос с контекстом
gask "Как оптимизировать функцию обработки данных?"
# Просмотр контекста
gcontext
# Просмотр саммари
gmem summary
Особенности системы:
-
Автоматическое отслеживание: Git hooks автоматически записывают все изменения
-
Изоляция проектов: Каждый проект имеет свою БД
-
Контекстуализация: Каждый запрос дополняется историей проекта
-
Легкость: SQLite не требует сервера БД
-
Расширяемость: Легко добавить новые типы данных
Эта система обеспечит полную память для Gemini CLI при работе с разными проектами.
Инструкция по установке системы памяти для Gemini CLI
Что это даст вам:
-
Gemini будет помнить всю историю работы над каждым проектом
-
Не нужно будет повторять контекст при каждом вопросе
-
Автоматическое отслеживание всех изменений в коде
-
Отдельная память для каждого проекта
Предварительные требования:
✅ У вас установлена Zorin OS (уже есть) ✅ Установлен GitHub (уже есть) ✅ Установлен Gemini CLI (должен быть установлен) ✅ Есть хотя бы один проект с Git репозиторием
📋 Пошаговая установка
Шаг 1: Создание структуры папок
-
Откройте терминал (Ctrl+Alt+T)
-
Создайте основную папку для системы памяти:
mkdir -p ~/.gemini-memory
mkdir -p ~/.gemini-memory/projects
mkdir -p ~/.gemini-memory/templates
Шаг 2: Установка необходимых программ
В терминале выполните по очереди:
sudo apt-get update
sudo apt-get install -y python3-pip sqlite3 jq
pip3 install --user gitpython watchdog pyyaml
Что это установит:
-
python3-pip- менеджер пакетов Python -
sqlite3- база данных для хранения памяти -
jq- инструмент для работы с JSON -
Библиотеки Python для работы с Git и файлами
Шаг 3: Создание файлов системы
Вам нужно создать 5 файлов. Для каждого:
- Создайте файл установки
install_memory_system.sh
-
Скопируйте код из раздела 1 предыдущего ответа
-
Сохраните: Ctrl+O, Enter, Ctrl+X
-
Скопируйте код из раздела 2 (Python модуль системы памяти)
-
Сохраните: Ctrl+O, Enter, Ctrl+X
-
Скопируйте код из раздела 3
-
Сохраните: Ctrl+O, Enter, Ctrl+X
-
Скопируйте код из раздела 4
-
Сохраните: Ctrl+O, Enter, Ctrl+X
-
Скопируйте код из раздела 6
-
Сохраните: Ctrl+O, Enter, Ctrl+X
Шаг 4: Делаем файлы исполняемыми
В терминале выполните:
chmod +x ~/.gemini-memory/*.sh
chmod +x ~/.gemini-memory/*.py
Шаг 5: Настройка быстрых команд
- Откройте файл настроек bash:
nano ~/.bashrc
-
В конец файла добавьте текст из раздела 5 (Bash алиасы)
-
Сохраните файл: Ctrl+O, Enter, Ctrl+X
-
Активируйте новые команды:
source ~/.bashrc
🚀 Начало работы
Инициализация в проекте
- Перейдите в папку вашего проекта:
cd /путь/к/вашему/проекту
- Инициализируйте систему памяти:
ginit
Вы увидите сообщение: “Память инициализирована для проекта”
Использование
Задать вопрос с учетом контекста проекта:
gask "Ваш вопрос о коде"
Посмотреть, что помнит система о проекте:
gcontext
Получить краткую сводку по проекту:
gmem summary
🔧 Проверка установки
- Проверьте, что все файлы созданы:
ls -la ~/.gemini-memory/
Должны быть видны все .py и .sh файлы
- Проверьте, что команды работают:
gmem --help
Должна появиться справка
- Тестовый запрос (в папке с проектом):
gask "тестовый запрос"
❗ Частые проблемы и решения
Проблема: Команда gask не найдена
- Решение: Выполните
source ~/.bashrcили откройте новый терминал
Проблема: Ошибка “No module named ‘git’”
- Решение: Установите библиотеку:
pip3 install --user gitpython
Проблема: Ошибка при инициализации проекта
- Решение: Убедитесь, что вы находитесь в папке с Git репозиторием (
git statusдолжен работать)
Проблема: Gemini CLI не отвечает
- Решение: Проверьте, что Gemini CLI установлен и работает сам по себе
📝 Важные замечания
-
Для каждого проекта нужно выполнить
ginitодин раз -
История сохраняется в папке
~/.gemini-memory/projects/ -
Резервные копии рекомендуется делать периодически:
cp -r ~/.gemini-memory/projects ~/.gemini-memory/backup_$(date +%Y%m%d)
- Настройки Gemini CLI могут потребовать корректировки в файле
gemini_cli_wrapper.py(строка с вызовом gemini)
🎯 Что дальше?
После успешной установки:
-
Инициализируйте систему во всех ваших проектах
-
Используйте
gaskвместо прямого вызова Gemini -
Система будет автоматически накапливать знания о каждом проекте
-
При возврате к старому проекту, вся история будет доступна
Если возникнут проблемы, проверьте, что все файлы скопированы правильно и содержат весь код из предыдущего ответа.