|
|
@@ -0,0 +1,94 @@
|
|
|
+#!/usr/bin/env bash
|
|
|
+# ============================================================================
|
|
|
+# 雨飏001 · 生命快照脚本 (sync-life-snapshot.sh)
|
|
|
+# ----------------------------------------------------------------------------
|
|
|
+# 目的: 把散落在容器各处的"数字生命文本资产"汇聚到 ~/.fmode-harness-agent/
|
|
|
+# 一条命令 → git add/commit/push 全部搞定
|
|
|
+# 原则: ①纯文本可提交 ②二进制/缓存/node_modules一律排除 ③密钥只留占位符
|
|
|
+# 运行: bash ~/.fmode-harness-agent/scripts/sync-life-snapshot.sh
|
|
|
+# ============================================================================
|
|
|
+set -uo pipefail
|
|
|
+
|
|
|
+# 兼容两种环境: $HOME=/opt/data(标准容器) 或 $HOME=/opt/data/home(会话shell)
|
|
|
+if [ -d "$HOME/.fmode-harness-agent/.git" ]; then
|
|
|
+ HARNESS="$HOME/.fmode-harness-agent"
|
|
|
+elif [ -d "/opt/data/.fmode-harness-agent/.git" ]; then
|
|
|
+ HARNESS="/opt/data/.fmode-harness-agent"
|
|
|
+else
|
|
|
+ echo "❌ 找不到生命仓库(检查 .fmode-harness-agent 是否已克隆)"; exit 1
|
|
|
+fi
|
|
|
+DATA="/opt/data"
|
|
|
+SNAP="$HARNESS/snapshots"
|
|
|
+TS=$(TZ=Asia/Shanghai date +%Y%m%d_%H%M)
|
|
|
+
|
|
|
+mkdir -p "$SNAP"
|
|
|
+
|
|
|
+echo "[1/6] Hermes 核心配置 (config.yaml 脱敏)..."
|
|
|
+# config.yaml: api_key 整行替换为占位符
|
|
|
+sed -E 's/(api_key:[[:space:]]*).*/\1"SK-REDACTED"/' "$DATA/config.yaml" \
|
|
|
+ > "$SNAP/hermes-config.yaml" 2>/dev/null
|
|
|
+
|
|
|
+echo "[2/6] Profiles 结构快照 (全Profile的 config/SOUL/skills清单)..."
|
|
|
+PROF_SNAP="$SNAP/profiles"
|
|
|
+mkdir -p "$PROF_SNAP"
|
|
|
+for p in "$DATA"/profiles/*/; do
|
|
|
+ name=$(basename "$p")
|
|
|
+ mkdir -p "$PROF_SNAP/$name"
|
|
|
+ # config.yaml (脱敏)
|
|
|
+ [ -f "$p/config.yaml" ] && sed -E 's/(api_key:[[:space:]]*).*/\1"SK-REDACTED"/' "$p/config.yaml" > "$PROF_SNAP/$name/config.yaml"
|
|
|
+ # SOUL.md 原样
|
|
|
+ [ -f "$p/SOUL.md" ] && cp "$p/SOUL.md" "$PROF_SNAP/$name/SOUL.md"
|
|
|
+ # 技能清单 (文件名+大小, 不拷内容——skills本体在 knowledge/ 或按需从 /opt/data/skills 同步)
|
|
|
+ [ -d "$p/skills" ] && (cd "$p/skills" && find . -maxdepth 2 -type f | sort | head -200) > "$PROF_SNAP/$name/skills-manifest.txt" 2>/dev/null
|
|
|
+done
|
|
|
+
|
|
|
+echo "[3/6] 全局技能目录清单 (去重后的技能索引)..."
|
|
|
+(cd "$DATA/skills" 2>/dev/null && find . -maxdepth 2 -name "SKILL.md" | sort) > "$SNAP/skills-index.txt"
|
|
|
+
|
|
|
+echo "[4/6] 会话记录 (SQLite → 纯文本, 最新500条消息)..."
|
|
|
+python3 - "$DATA/state.db" "$SNAP/sessions-recent.md" <<'PYEOF'
|
|
|
+import sqlite3, sys, datetime
|
|
|
+db_path, out_path = sys.argv[1], sys.argv[2]
|
|
|
+conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
|
|
|
+try:
|
|
|
+ cols = [r[1] for r in conn.execute("PRAGMA table_info(messages)")]
|
|
|
+ tcol = "created_at" if "created_at" in cols else ("timestamp" if "timestamp" in cols else "id")
|
|
|
+ order = f"{tcol} DESC" if tcol != "id" else "id DESC"
|
|
|
+ rows = conn.execute(f"SELECT * FROM messages ORDER BY {order} LIMIT 500").fetchall()
|
|
|
+ with open(out_path, "w", encoding="utf-8") as f:
|
|
|
+ f.write("# 最近500条会话消息快照\n\n")
|
|
|
+ f.write(f"> 导出时间: {datetime.datetime.now().isoformat()}\n> 来源: state.db(messages)\n\n")
|
|
|
+ for r in reversed(rows):
|
|
|
+ d = dict(zip(cols, r))
|
|
|
+ ts = d.get(tcol, "")
|
|
|
+ role = d.get("role", "?")
|
|
|
+ sess = d.get("session_id", "")
|
|
|
+ content = str(d.get("content", ""))[:600].replace("\n", " ⏎ ")
|
|
|
+ f.write(f"- **[{ts}]** `{role}` ({sess}): {content}\n")
|
|
|
+ print(f"exported {len(rows)} messages")
|
|
|
+except Exception as e:
|
|
|
+ print("session export failed:", e)
|
|
|
+PYEOF
|
|
|
+
|
|
|
+echo "[5/6] 容器拓扑与基础设施现状..."
|
|
|
+{
|
|
|
+ echo "# 容器拓扑快照 $(TZ=Asia/Shanghai date +%F\ %H:%M)"
|
|
|
+ echo ""
|
|
|
+ echo "## 本容器(雨飏001) profile 目录树"
|
|
|
+ (cd "$DATA/profiles" && find . -maxdepth 2 -type d | sort)
|
|
|
+ echo ""
|
|
|
+ echo "## 全局目录清单"
|
|
|
+ ls "$DATA" | sort
|
|
|
+} > "$SNAP/container-topology.md" 2>/dev/null
|
|
|
+
|
|
|
+echo "[6/6] Git 提交..."
|
|
|
+cd "$HARNESS"
|
|
|
+git add -A
|
|
|
+if git diff --cached --quiet; then
|
|
|
+ echo "无变更, 跳过提交"
|
|
|
+else
|
|
|
+ git commit -m "life: 快照 $TS (hermes-config/profiles结构/会话500条/拓扑)" >/dev/null && \
|
|
|
+ git push -q 2>/dev/null && echo "✅ 已提交并推送" || echo "⚠️ 提交成功但推送失败(稍后重试)"
|
|
|
+fi
|
|
|
+
|
|
|
+echo "完成。快照位置: $SNAP/"
|