chore: move cron scripts to ~/.openclaw/cron/scripts
- Move scripts from ~/work/backup/ to ~/.openclaw/cron/scripts/ - Update cron jobs.json to use new script paths - Scripts: backup_openclaw.sh, evolver-run.sh, zq-sync.sh, git-auto-sync.sh, ai-conversation-logger.sh
This commit is contained in:
+31
-4
@@ -17,7 +17,7 @@
|
||||
"wakeMode": "now",
|
||||
"payload": {
|
||||
"kind": "agentTurn",
|
||||
"message": "执行备份脚本:/home/starmen1265/work/backup/backup_openclaw.sh"
|
||||
"message": "执行备份脚本:/home/starmen1265/.openclaw/cron/scripts/backup_openclaw.sh"
|
||||
},
|
||||
"delivery": {
|
||||
"mode": "announce"
|
||||
@@ -46,7 +46,7 @@
|
||||
"wakeMode": "now",
|
||||
"payload": {
|
||||
"kind": "agentTurn",
|
||||
"message": "执行每日 capability-evolver 任务:\n\n1. 执行脚本:bash ~/work/backup/evolver-run.sh\n2. 读取输出:cat ~/work/backup/evolver-output.txt\n3. 将完整的修改内容(包含 Git 备份信息和本次变更)通过 feishu 发送给蒋先生\n\n如果本次无任何变更,回复 '今日无变更' 即可。",
|
||||
"message": "执行每日 capability-evolver 任务:\n\n1. 执行脚本:bash ~/.openclaw/cron/scripts/evolver-run.sh\n2. 读取输出:cat ~/work/backup/evolver-output.txt\n3. 将完整的修改内容(包含 Git 备份信息和本次变更)通过 feishu 发送给蒋先生\n\n如果本次无任何变更,回复 '今日无变更' 即可。",
|
||||
"model": "g47f",
|
||||
"thinking": "off",
|
||||
"timeoutSeconds": 300
|
||||
@@ -80,7 +80,7 @@
|
||||
"wakeMode": "now",
|
||||
"payload": {
|
||||
"kind": "systemEvent",
|
||||
"text": "执行知识库同步:bash ~/work/backup/zq-sync.sh"
|
||||
"text": "执行知识库同步:bash ~/.openclaw/cron/scripts/zq-sync.sh"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772823600000,
|
||||
@@ -106,7 +106,7 @@
|
||||
"wakeMode": "now",
|
||||
"payload": {
|
||||
"kind": "systemEvent",
|
||||
"text": "执行 OpenClaw 备份:bash ~/work/backup/git-auto-sync.sh"
|
||||
"text": "执行 OpenClaw 备份:bash ~/.openclaw/cron/scripts/git-auto-sync.sh"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772823600000,
|
||||
@@ -115,6 +115,33 @@
|
||||
"lastDurationMs": 9616,
|
||||
"consecutiveErrors": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "3245fca7-045b-4977-8fab-020f6df2e453",
|
||||
"agentId": "haonan",
|
||||
"name": "ai-conversation-logger",
|
||||
"description": "每天早上7点整理与各个 AI 代理的对话记录",
|
||||
"enabled": true,
|
||||
"createdAtMs": 1772776369645,
|
||||
"updatedAtMs": 1772777284202,
|
||||
"schedule": {
|
||||
"kind": "cron",
|
||||
"expr": "0 7 * * *"
|
||||
},
|
||||
"sessionTarget": "isolated",
|
||||
"wakeMode": "now",
|
||||
"payload": {
|
||||
"kind": "agentTurn",
|
||||
"message": "请执行 ~/.openclaw/cron/scripts/ai-conversation-logger.sh 脚本来整理昨天的 AI 对话记录。完成后汇报整理结果。",
|
||||
"timeoutSeconds": 300
|
||||
},
|
||||
"delivery": {
|
||||
"mode": "announce",
|
||||
"channel": "last"
|
||||
},
|
||||
"state": {
|
||||
"nextRunAtMs": 1772838000000
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Executable
+212
@@ -0,0 +1,212 @@
|
||||
#!/bin/bash
|
||||
# AI 对话记录定时任务
|
||||
# 功能:每天凌晨整理与各个 AI 代理的对话记录
|
||||
|
||||
set -e
|
||||
|
||||
OUTPUT_BASE="$HOME/work/zq/30.资源/AI会话历史"
|
||||
ZQ_DIR="$HOME/work/zq"
|
||||
OPENCLAW_DIR="$HOME/.openclaw"
|
||||
LOG_FILE="$HOME/work/backup/ai-conversation-logger.log"
|
||||
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
|
||||
CURRENT_MONTH=$(date -d "yesterday" +%Y-%m)
|
||||
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
log "=== AI 对话记录整理开始 ==="
|
||||
log "处理日期: $YESTERDAY"
|
||||
|
||||
# 从 NAS 拉取最新内容
|
||||
log "从 NAS 拉取最新内容..."
|
||||
cd "$ZQ_DIR" || { log "错误:无法进入 $ZQ_DIR"; exit 1; }
|
||||
rclone sync "nas-webdav:/home/Drive/工作区/张青/工作区/" "$ZQ_DIR/" \
|
||||
--exclude ".git/" --exclude ".gitignore" \
|
||||
--log-level INFO >> "$LOG_FILE" 2>&1 || log "警告:rclone 拉取失败"
|
||||
log "同步完成"
|
||||
|
||||
mkdir -p "$OUTPUT_BASE"
|
||||
AGENTS=$(ls -1 "$OPENCLAW_DIR/agents/" 2>/dev/null | grep -v "^\." || true)
|
||||
|
||||
if [[ -z "$AGENTS" ]]; then
|
||||
log "未找到任何代理目录"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "发现代理: $AGENTS"
|
||||
|
||||
# Python 脚本处理对话记录
|
||||
python3 << 'PYEOF'
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
OUTPUT_BASE = os.path.expanduser("~/work/zq/30.资源/AI会话历史")
|
||||
OPENCLAW_DIR = os.path.expanduser("~/.openclaw/agents")
|
||||
YESTERDAY = os.environ.get('YESTERDAY', '2026-03-05')
|
||||
CURRENT_MONTH = os.environ.get('CURRENT_MONTH', '2026-03')
|
||||
|
||||
def clean_user_message(text):
|
||||
if not text: return ""
|
||||
if '[Feishu' in text:
|
||||
match = re.search(r'\[Feishu[^\]]+\]\s*[^:]+:\s*(.+)', text, re.DOTALL)
|
||||
if match:
|
||||
content = match.group(1)
|
||||
content = re.sub(r'\s*\[message_id:[^\]]+\]\s*$', '', content)
|
||||
return content.strip()
|
||||
if text.startswith('System:') and '[Feishu' not in text: return ""
|
||||
return text.strip()
|
||||
|
||||
def extract_tags(messages):
|
||||
tags = set()
|
||||
all_text = ' '.join([m['content'] for m in messages]).lower()
|
||||
tag_rules = {
|
||||
'AI/LLM': ['ai', 'llm', '模型', 'gpt', 'claude', '推理', 'token'],
|
||||
'OpenClaw': ['openclaw', 'gateway', 'agent', '代理', '会话'],
|
||||
'知识库': ['知识库', 'kb', '归档', 'memory'],
|
||||
'编程开发': ['代码', 'code', '开发', 'git', 'python', 'bash'],
|
||||
'部署运维': ['部署', 'deploy', '服务器', 'docker', '配置'],
|
||||
'游戏开发': ['ue', 'unreal', 'unity', '游戏', '3d'],
|
||||
'iOS/Apple': ['ios', 'mac', 'xcode', 'apple', 'swift'],
|
||||
'问题解决': ['报错', '错误', 'error', '怎么', '如何'],
|
||||
'技术探讨': ['探讨', '讨论', '原理', '架构', '研究'],
|
||||
'任务规划': ['计划', '规划', 'todo', '待办', '任务'],
|
||||
'定时任务': ['cron', '定时', '自动', '备份'],
|
||||
'飞书相关': ['飞书', 'feishu'],
|
||||
}
|
||||
for tag, keywords in tag_rules.items():
|
||||
for kw in keywords:
|
||||
if kw in all_text:
|
||||
tags.add(tag)
|
||||
break
|
||||
return sorted(list(tags))[:5] if tags else ['对话记录']
|
||||
|
||||
def parse_jsonl(filepath):
|
||||
messages = []
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line: continue
|
||||
try:
|
||||
entry = json.loads(line)
|
||||
except: continue
|
||||
if entry.get('type') != 'message': continue
|
||||
msg = entry.get('message', {})
|
||||
role = msg.get('role', '')
|
||||
if role not in ['user', 'assistant']: continue
|
||||
content = msg.get('content', '')
|
||||
if isinstance(content, list):
|
||||
texts = []
|
||||
for p in content:
|
||||
if isinstance(p, dict) and p.get('type') == 'text' and p.get('type') not in ['thinking', 'toolCall']:
|
||||
t = p.get('text', '')
|
||||
if t: texts.append(t)
|
||||
content = '\n\n'.join(texts)
|
||||
if role == 'user': content = clean_user_message(content)
|
||||
if content and content.strip():
|
||||
messages.append({'role': role, 'content': content.strip(), 'timestamp': entry.get('timestamp', 0)})
|
||||
return messages
|
||||
|
||||
def gen_md(agent, date, messages):
|
||||
if not messages: return "", 0
|
||||
messages.sort(key=lambda x: x.get('timestamp', 0))
|
||||
seen, unique = set(), []
|
||||
for m in messages:
|
||||
k = (m['role'], m['content'][:100])
|
||||
if k not in seen: seen.add(k); unique.append(m)
|
||||
tags = extract_tags(unique)
|
||||
tags_str = ', '.join([f'"{t}"' for t in tags])
|
||||
md = f"""---
|
||||
agent: {agent}
|
||||
date: {date}
|
||||
generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||
messages: {len(unique)}
|
||||
tags: [{tags_str}]
|
||||
---
|
||||
|
||||
# {agent} 对话记录 - {date}
|
||||
|
||||
**标签**: {', '.join(tags)}
|
||||
|
||||
共 {len(unique)} 条消息
|
||||
|
||||
---
|
||||
"""
|
||||
for m in unique:
|
||||
icon = "👤" if m['role'] == 'user' else "🤖"
|
||||
name = "用户" if m['role'] == 'user' else "助手"
|
||||
md += f"\n### {icon} {name}\n\n{m['content']}\n\n---\n"
|
||||
return md, len(unique)
|
||||
|
||||
agents = [d for d in os.listdir(OPENCLAW_DIR) if not d.startswith('.')]
|
||||
for agent in agents:
|
||||
sdir = os.path.join(OPENCLAW_DIR, agent, "sessions")
|
||||
if not os.path.isdir(sdir): continue
|
||||
files = []
|
||||
for f in os.listdir(sdir):
|
||||
if f.endswith('.jsonl') and not f.endswith('.lock') and '.deleted' not in f:
|
||||
fp = os.path.join(sdir, f)
|
||||
if datetime.fromtimestamp(os.stat(fp).st_mtime).strftime('%Y-%m-%d') == YESTERDAY:
|
||||
files.append(fp)
|
||||
if not files: continue
|
||||
msgs = []
|
||||
for fp in files: msgs.extend(parse_jsonl(fp))
|
||||
if not msgs: continue
|
||||
md, cnt = gen_md(agent, YESTERDAY, msgs)
|
||||
if md:
|
||||
odir = os.path.join(OUTPUT_BASE, agent, CURRENT_MONTH)
|
||||
os.makedirs(odir, exist_ok=True)
|
||||
ofile = os.path.join(odir, f"对话-{YESTERDAY}.md")
|
||||
with open(ofile, 'w', encoding='utf-8') as f: f.write(md)
|
||||
print(f"{agent}: {cnt} 条消息, 标签: {extract_tags(msgs)}")
|
||||
|
||||
# 更新月度汇总
|
||||
for agent in agents:
|
||||
mdir = os.path.join(OUTPUT_BASE, agent, CURRENT_MONTH)
|
||||
if not os.path.isdir(mdir): continue
|
||||
dfiles = list(Path(mdir).glob("对话-*.md"))
|
||||
if not dfiles: continue
|
||||
sfile = os.path.join(mdir, f"汇总-{CURRENT_MONTH}.md")
|
||||
smd = f"""---
|
||||
agent: {agent}
|
||||
month: {CURRENT_MONTH}
|
||||
generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||
days: {len(dfiles)}
|
||||
---
|
||||
|
||||
# {agent} 月度汇总 - {CURRENT_MONTH}
|
||||
|
||||
## 概览
|
||||
- 对话天数:{len(dfiles)} 天
|
||||
- 生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||
|
||||
## 每日对话索引
|
||||
|
||||
"""
|
||||
for df in sorted(dfiles):
|
||||
d = df.stem.replace("对话-", "")
|
||||
smd += f"- [{d}](./对话-{d}.md)\n"
|
||||
with open(sfile, 'w', encoding='utf-8') as f: f.write(smd)
|
||||
print(f"{agent}: 更新汇总")
|
||||
print("处理完成!")
|
||||
PYEOF
|
||||
|
||||
log "=== AI 对话记录整理完成 ==="
|
||||
|
||||
# 推送到 Git 和 NAS
|
||||
cd "$ZQ_DIR"
|
||||
CHANGES=$(git status --porcelain 2>/dev/null || true)
|
||||
if [[ -n "$CHANGES" ]]; then
|
||||
log "提交到 Git..."
|
||||
git add -A >> "$LOG_FILE" 2>&1
|
||||
git commit -m "AI对话记录: $YESTERDAY" >> "$LOG_FILE" 2>&1 || true
|
||||
git push origin main >> "$LOG_FILE" 2>&1 || log "警告:Git push 失败"
|
||||
fi
|
||||
|
||||
log "推送到 NAS..."
|
||||
rclone copy "$OUTPUT_BASE" "nas-webdav:/home/Drive/工作区/张青/工作区/30.资源/AI会话历史/" \
|
||||
--log-level INFO >> "$LOG_FILE" 2>&1 || log "警告:rclone 推送失败"
|
||||
log "推送完成"
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# 备份 openclaw.json
|
||||
BACKUP_DIR="/home/starmen1265/work/backup"
|
||||
SOURCE_FILE="/home/starmen1265/.openclaw/openclaw.json"
|
||||
|
||||
# 创建备份目录(如果不存在)
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# 备份文件,文件名包含日期时间
|
||||
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
|
||||
cp "$SOURCE_FILE" "$BACKUP_DIR/openclaw.json.$TIMESTAMP"
|
||||
|
||||
# 只保留最近30个备份
|
||||
cd "$BACKUP_DIR"
|
||||
ls -t openclaw.json.* | tail -n +31 | xargs -r rm
|
||||
|
||||
echo "Backup completed: openclaw.json.$TIMESTAMP"
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
# Capability Evolver 定期运行脚本
|
||||
# 策略:使用 repair-only 模式,仅修复问题不做大改动
|
||||
|
||||
EVOLVER_DIR="$HOME/.openclaw/skills/capability-evolver"
|
||||
OUTPUT_FILE="$HOME/work/backup/evolver-output.txt"
|
||||
OPENCLAW_DIR="$HOME/.openclaw"
|
||||
|
||||
echo "=== Capability Evolver 运行开始 ===" > "$OUTPUT_FILE"
|
||||
echo "时间: $(date)" >> "$OUTPUT_FILE"
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
|
||||
# 切换到 openclaw 目录
|
||||
cd "$OPENCLAW_DIR"
|
||||
|
||||
# 推送到远端(如果有远端)
|
||||
if git remote get-url origin &>/dev/null; then
|
||||
echo "=== 推送到远端 ===" >> "$OUTPUT_FILE"
|
||||
git push origin main >> "$OUTPUT_FILE" 2>&1
|
||||
echo "推送完成" >> "$OUTPUT_FILE"
|
||||
else
|
||||
echo "无远端配置,跳过推送" >> "$OUTPUT_FILE"
|
||||
fi
|
||||
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
|
||||
# 检查是否有未提交的更改
|
||||
if [[ -n $(git status --porcelain) ]]; then
|
||||
echo "发现有未提交的更改,先提交..." >> "$OUTPUT_FILE"
|
||||
git add -A
|
||||
git commit -m "Auto backup before evolver run - $(date)" 2>/dev/null
|
||||
fi
|
||||
|
||||
# 创建备份分支
|
||||
BACKUP_BRANCH="backup/evolver-$(date +%Y%m%d-%H%M%S)"
|
||||
echo "创建备份分支: $BACKUP_BRANCH" >> "$OUTPUT_FILE"
|
||||
git branch -D "$BACKUP_BRANCH" 2>/dev/null || true
|
||||
git branch "$BACKUP_BRANCH" 2>/dev/null
|
||||
|
||||
# 推送备份分支
|
||||
if git remote get-url origin &>/dev/null; then
|
||||
git push origin "$BACKUP_BRANCH" >> "$OUTPUT_FILE" 2>&1 || echo "备份分支推送失败" >> "$OUTPUT_FILE"
|
||||
fi
|
||||
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "=== Git 备份完成 ===" >> "$OUTPUT_FILE"
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
|
||||
# 运行 evolver - 使用 repair-only 策略确保安全
|
||||
cd "$EVOLVER_DIR"
|
||||
export EVOLVE_STRATEGY="repair-only"
|
||||
echo "=== 运行 Capability Evolver (repair-only 模式) ===" >> "$OUTPUT_FILE"
|
||||
node index.js run >> "$OUTPUT_FILE" 2>&1
|
||||
EXIT_CODE=$?
|
||||
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "=== Evolver 运行完成 (exit code: $EXIT_CODE) ===" >> "$OUTPUT_FILE"
|
||||
|
||||
# 检查变更
|
||||
cd "$OPENCLAW_DIR"
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "=== 本次变更 ===" >> "$OUTPUT_FILE"
|
||||
git status --short >> "$OUTPUT_FILE"
|
||||
|
||||
# 如果有变更,推送
|
||||
if [[ -n $(git status --porcelain) ]]; then
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "=== 推送变更到远端 ===" >> "$OUTPUT_FILE"
|
||||
git add -A
|
||||
git commit -m "Evolver auto evolution - $(date)" 2>/dev/null || true
|
||||
git push origin main >> "$OUTPUT_FILE" 2>&1 || echo "推送失败" >> "$OUTPUT_FILE"
|
||||
fi
|
||||
|
||||
echo "" >> "$OUTPUT_FILE"
|
||||
echo "=== 输出完成 ===" >> "$OUTPUT_FILE"
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 自动检查并提交 git 修改
|
||||
|
||||
cd ~/.openclaw
|
||||
git add -A
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "自动同步: $(date '+%Y-%m-%d %H:%M')"
|
||||
git push origin main
|
||||
fi
|
||||
|
||||
cd ~/.openclaw/extensions
|
||||
git add -A
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "自动同步: $(date '+%Y-%m-%d %H:%M')"
|
||||
git push origin main
|
||||
fi
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
# 知识库同步和备份脚本
|
||||
|
||||
ZQ_DIR="$HOME/work/zq"
|
||||
LOG_FILE="$HOME/work/zq-sync.log"
|
||||
DATE=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
log() {
|
||||
echo "[$DATE] $1" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
log "========== 开始同步 =========="
|
||||
|
||||
cd "$ZQ_DIR" || exit 1
|
||||
|
||||
# 1. 先拉取远程更新
|
||||
log "拉取远程更新..."
|
||||
git pull origin main --rebase >> "$LOG_FILE" 2>&1
|
||||
|
||||
# 2. 从 NAS WebDAV 拉取最新内容(排除 .git 目录)
|
||||
log "从 NAS 拉取更新..."
|
||||
rclone sync "nas-webdav:/home/Drive/工作区/张青/工作区/" "$ZQ_DIR/" \
|
||||
--exclude ".git/" \
|
||||
--exclude ".gitignore" \
|
||||
--log-level INFO >> "$LOG_FILE" 2>&1
|
||||
|
||||
# 3. 检查是否有变更
|
||||
CHANGES=$(git status --porcelain)
|
||||
|
||||
if [ -n "$CHANGES" ]; then
|
||||
log "检测到变更,提交到 Git..."
|
||||
git add -A
|
||||
git commit -m "自动备份: $DATE" >> "$LOG_FILE" 2>&1
|
||||
|
||||
# 4. 推送到 Gitea
|
||||
log "推送到 Gitea..."
|
||||
git push origin main >> "$LOG_FILE" 2>&1
|
||||
log "备份完成!"
|
||||
else
|
||||
log "没有变更,跳过提交。"
|
||||
fi
|
||||
|
||||
log "========== 同步完成 =========="
|
||||
Reference in New Issue
Block a user