#!/usr/bin/env python3 """ memory-md-hot 每日维护脚本 维护 memory.md 文件的事件流水和重要事件 保留所有历史记录,需配合 memory-md-archive 技能归档 """ import os import re import sys from datetime import datetime from pathlib import Path # 配置 MEMORY_FILE = Path.home() / ".openclaw" / "workspace" / "MEMORY.md" ARCHIVE_THRESHOLD_KB = 50 # 建议归档的阈值(仅提示,不强制) def read_memory_file(): """读取 memory.md 文件内容""" if not MEMORY_FILE.exists(): return "" return MEMORY_FILE.read_text(encoding='utf-8') def write_memory_file(content): """写入 memory.md 文件""" MEMORY_FILE.parent.mkdir(parents=True, exist_ok=True) MEMORY_FILE.write_text(content, encoding='utf-8') def get_file_size(): """获取文件大小(字节)""" if not MEMORY_FILE.exists(): return 0 return MEMORY_FILE.stat().st_size def parse_date_from_line(line): """从行中提取日期(YYYY-MM-DD 格式)""" match = re.search(r'(\d{4}-\d{2}-\d{2})', line) if match: try: return datetime.strptime(match.group(1), '%Y-%m-%d').date() except ValueError: return None return None def extract_event_entries(content): """ 从内容中提取事件条目 返回: (important_events, daily_events) 元组 """ important_events = [] daily_events = [] lines = content.split('\n') in_important = False in_daily = False for line in lines: stripped = line.strip() # 检测区块 if '重要事件' in stripped and stripped.startswith('#'): in_important = True in_daily = False continue elif ('事件流水' in stripped) and stripped.startswith('#'): in_important = False in_daily = True continue elif stripped.startswith('#') and in_important: in_important = False elif stripped.startswith('#') and in_daily: in_daily = False # 收集事件 if in_important and stripped.startswith('-'): if len(stripped) > 10: # 过滤空行和短行 important_events.append(line) elif in_daily and (stripped.startswith('-') or stripped.startswith('*')): daily_events.append(line) return important_events, daily_events def generate_default_content(): """生成默认的 memory.md 内容""" today = datetime.now().strftime('%Y-%m-%d') return f"""# MEMORY.md - 热记忆 / 活跃记忆 > 本文件记录近期发生的重要事情,详细信息可通过记忆检索获取。 --- ## 🔔 重要事件 > 记录具有全局长期性影响的重要决策和事件。 > 添加重要事件时会告知用户。 --- ## 📅 事件流水 > 按天分组,每天主要事情的概要。 > 所有记录永久保留,可使用 memory-md-archive 技能归档瘦身。 ### {{today}} - {today} 10:00 | memory.md 初始化 | 热记忆系统 --- *文件大小: ~0.5KB | 事件数: 1* *维护脚本: `memory-md-hot/scripts/daily_maintenance.py`* *归档提示: 文件较大时请使用 memory-md-archive 技能归档* """.format(today=today) def update_memory_file(new_daily_events=None, important_event=None): """ 更新 memory.md 文件 Args: new_daily_events: 新的每日事件列表 [(date, time, summary, keywords), ...] important_event: 重要事件元组 (date, time, summary, keywords) 或 None Returns: dict: 操作结果 """ result = { 'success': True, 'added_daily': 0, 'added_important': False, 'current_size_kb': 0, 'total_events': 0, 'archive_suggested': False, 'messages': [] } # 读取现有内容 content = read_memory_file() if not content: content = generate_default_content() # 提取现有事件 existing_important, existing_daily = extract_event_entries(content) # 保留所有现有日常事件(不再移除旧记录) all_daily = list(existing_daily) # 添加新的日常事件 if new_daily_events: for event in new_daily_events: date, time, summary, keywords = event entry = f"- {date} {time} | {summary} | {keywords}" # 检查是否已存在 if not any(entry.strip() in existing.strip() for existing in all_daily): all_daily.append(entry) result['added_daily'] += 1 # 添加重要事件 new_important = list(existing_important) if important_event: date, time, summary, keywords = important_event entry = f"- {date} {time} | {summary} | {keywords}" new_important.append(entry) result['added_important'] = True result['messages'].append(f"重要事件已记录: {summary}") # 重新构建文件内容 today = datetime.now().strftime('%Y-%m-%d') # 按日期分组日常事件 daily_by_date = {} for line in all_daily: date = parse_date_from_line(line) if date: date_str = date.strftime('%Y-%m-%d') if date_str not in daily_by_date: daily_by_date[date_str] = [] daily_by_date[date_str].append(line) # 构建日常事件区块 daily_sections = [] for date_str in sorted(daily_by_date.keys(), reverse=True): daily_sections.append(f"\n### {date_str}\n") daily_sections.extend([f"{line}\n" for line in daily_by_date[date_str]]) daily_content = ''.join(daily_sections) if daily_sections else f"\n### {today}\n\n- {today} --:-- | 暂无记录 | --\n" # 构建重要事件区块 important_content = '\n'.join(new_important) if new_important else "" # 计算统计 total_events = len(all_daily) + len(new_important) result['total_events'] = total_events # 组装最终内容 current_size = get_file_size() result['current_size_kb'] = round(current_size / 1024, 2) new_content = f"""# MEMORY.md - 热记忆 / 活跃记忆 > 本文件记录近期发生的重要事情,详细信息可通过记忆检索获取。 --- ## 🔔 重要事件 > 记录具有全局长期性影响的重要决策和事件。 > 添加重要事件时会告知用户。 {important_content} --- ## 📅 事件流水 > 按天分组,每天主要事情的概要。 > 所有记录永久保留,可使用 memory-md-archive 技能归档瘦身。 {daily_content} --- *文件大小: ~{result['current_size_kb']:.1f}KB | 事件数: {total_events}* *维护脚本: `memory-md-hot/scripts/daily_maintenance.py`* *归档提示: 文件较大时请使用 memory-md-archive 技能归档* """ # 写入文件 write_memory_file(new_content) # 检查是否需要建议归档 new_size = get_file_size() result['current_size_kb'] = round(new_size / 1024, 2) if result['current_size_kb'] > ARCHIVE_THRESHOLD_KB: result['archive_suggested'] = True result['messages'].append(f"提示: 文件大小 ({result['current_size_kb']}KB) 超过 {ARCHIVE_THRESHOLD_KB}KB,建议使用 memory-md-archive 技能归档") return result def get_stats(): """获取文件统计信息""" content = read_memory_file() if not content: return { 'size_bytes': 0, 'size_kb': 0, 'total_events': 0, 'important_events': 0, 'daily_events': 0, 'archive_suggested': False } important, daily = extract_event_entries(content) size = get_file_size() size_kb = round(size / 1024, 2) return { 'size_bytes': size, 'size_kb': size_kb, 'total_events': len(important) + len(daily), 'important_events': len(important), 'daily_events': len(daily), 'archive_suggested': size_kb > ARCHIVE_THRESHOLD_KB } def main(): """主函数 - 供命令行调用""" if len(sys.argv) < 2: print("用法: python daily_maintenance.py [args]") print("") print("命令:") print(" update - 执行每日更新") print(" stats - 查看文件统计") print(" add-daily