🎉 init: 小龙的工作空间
This commit is contained in:
Executable
+269
@@ -0,0 +1,269 @@
|
||||
#!/usr/bin/env bash
|
||||
# session-compact.sh — 会话压缩与快速存档 + Write Gate 前置检查
|
||||
#
|
||||
# v3 — 加入 pre-compact 钩子:上下文压缩前自动扫描未保存的纠正/决策/承诺
|
||||
# v2 — 加入 Write Gate 自动路由:preference/correction/decision 触发寄存器写入
|
||||
#
|
||||
# 用法:
|
||||
# bash scripts/session-compact.sh save "任何想记住的内容"
|
||||
# bash scripts/session-compact.sh save --type preference "偏好内容"
|
||||
# bash scripts/session-compact.sh save --type correction "纠正内容"
|
||||
# bash scripts/session-compact.sh save --type decision "决策内容"
|
||||
# bash scripts/session-compact.sh pre-compact # 上下文压缩前扫描 + 同步
|
||||
# bash scripts/session-compact.sh status # 看会话统计
|
||||
# bash scripts/session-compact.sh flush # 触发 Dream Cycle 同步
|
||||
# bash scripts/session-compact.sh check # Write Gate 诊断
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
WORKSPACE="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
MEMORY_SERVER="http://111.229.145.18"
|
||||
|
||||
# 加载环境变量(MEMORY_API_KEY 等)
|
||||
if [ -z "${MEMORY_API_KEY:-}" ] && [ -f ~/.zshrc ]; then
|
||||
MEMORY_API_KEY=$(grep '^export MEMORY_API_KEY=' ~/.zshrc 2>/dev/null | cut -d'"' -f2 || true)
|
||||
fi
|
||||
export MEMORY_API_KEY
|
||||
DAILY="$WORKSPACE/memory/daily/$(date +%Y-%m-%d).md"
|
||||
REGISTERS="$WORKSPACE/memory/registers"
|
||||
SESSION_LOG="$WORKSPACE/memory/.session-compact.log"
|
||||
|
||||
# ── Write Gate 路由 ──────────────────────────────────────
|
||||
|
||||
write_to_register() {
|
||||
local type="$1" content="$2" timestamp
|
||||
timestamp=$(date '+%Y-%m-%d %H:%M')
|
||||
|
||||
case "$type" in
|
||||
preference)
|
||||
printf "\n| %s | %s | %s | session-compact | medium |\n" \
|
||||
"$(wc -l < "$REGISTERS/preferences.md" | tr -d ' ')" \
|
||||
"$content" "$timestamp" >> "$REGISTERS/preferences.md"
|
||||
echo " 📝 → preferences 寄存器"
|
||||
;;
|
||||
correction)
|
||||
printf "\n[correction: %s]\n- **new**: %s\n- **source**: session-compact\n" \
|
||||
"$timestamp" "$content" >> "$REGISTERS/open-loops.md"
|
||||
echo " 🔧 → open-loops 寄存器 (correction)"
|
||||
;;
|
||||
decision)
|
||||
printf "\n- %s: %s (session-compact)\n" "$timestamp" "$content" \
|
||||
>> "$WORKSPACE/memory/vault.md"
|
||||
echo " 📋 → vault.md (decision)"
|
||||
;;
|
||||
event)
|
||||
# 事件记录到 daily/ 已足够,不写寄存器
|
||||
echo " 📌 → daily/ (event,不写寄存器)"
|
||||
;;
|
||||
fact|behavior|code|rule|tool|project)
|
||||
# 新类型:写入 vault.md 的决策时间线
|
||||
printf "\n- %s: [%s] %s (session-compact)\n" "$timestamp" "$type" "$content" \
|
||||
>> "$WORKSPACE/memory/vault.md"
|
||||
echo " 📋 → vault.md ($type)"
|
||||
;;
|
||||
*)
|
||||
echo " ⚠️ 未知类型 '$type',仅写入 daily/"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ── 命令处理 ─────────────────────────────────────────────
|
||||
|
||||
case "${1:-help}" in
|
||||
save)
|
||||
shift
|
||||
# 解析参数
|
||||
type=""
|
||||
content=""
|
||||
recall_context=""
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--type) type="$2"; shift 2 ;;
|
||||
--type=*) type="${1#*=}"; shift ;;
|
||||
--recall-context) recall_context="$2"; shift 2 ;;
|
||||
--recall-context=*) recall_context="${1#*=}"; shift ;;
|
||||
*) content="$1"; shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$content" ]; then
|
||||
echo "用法: bash scripts/session-compact.sh save [--type <type>] [--recall-context <context>] <内容>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Step 1: LLM Write Gate 判断(如果未指定 type)──
|
||||
if [ -z "$type" ] && [ -f "$WORKSPACE/scripts/memory-write-gate.sh" ]; then
|
||||
echo " 🧠 Write Gate LLM 判断中..."
|
||||
GATE_RESULT=$(echo "$content" | bash "$WORKSPACE/scripts/memory-write-gate.sh" 2>/dev/null || echo '{"should_remember":false}')
|
||||
SHOULD_REMEMBER=$(echo "$GATE_RESULT" | jq -r '.should_remember // false' 2>/dev/null || echo "false")
|
||||
|
||||
if [ "$SHOULD_REMEMBER" = "true" ]; then
|
||||
type=$(echo "$GATE_RESULT" | jq -r '.type // ""' 2>/dev/null || echo "")
|
||||
importance=$(echo "$GATE_RESULT" | jq -r '.importance // 0.5' 2>/dev/null || echo "0.5")
|
||||
gate_content=$(echo "$GATE_RESULT" | jq -r '.content // ""' 2>/dev/null || echo "")
|
||||
gate_recall=$(echo "$GATE_RESULT" | jq -r '.recall_context // [] | join(",")' 2>/dev/null || echo "")
|
||||
gate_tags=$(echo "$GATE_RESULT" | jq -r '.tags // [] | join(",")' 2>/dev/null || echo "")
|
||||
|
||||
# 用 LLM 精炼的内容覆盖原始内容
|
||||
[ -n "$gate_content" ] && [ "$gate_content" != "null" ] && content="$gate_content"
|
||||
# 用 LLM 的 recall_context(如果用户没指定)
|
||||
[ -z "$recall_context" ] && [ -n "$gate_recall" ] && [ "$gate_recall" != "null" ] && recall_context="$gate_recall"
|
||||
|
||||
echo " ✅ Write Gate: 值得记 (type=$type, importance=$importance)"
|
||||
else
|
||||
gate_reason=$(echo "$GATE_RESULT" | jq -r '.reason // "not_important"' 2>/dev/null || echo "not_important")
|
||||
echo " ℹ️ Write Gate: 不值得记 ($gate_reason),仅写入 daily/"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Step 2: 写入 daily/(带 YAML frontmatter)──
|
||||
mkdir -p "$(dirname "$DAILY")"
|
||||
memory_id="mem_$(date +%Y%m%d)_$(openssl rand -hex 3 2>/dev/null || date +%s)"
|
||||
|
||||
# 如果有 recall_context,用 YAML frontmatter 格式
|
||||
if [ -n "$type" ] || [ -n "$recall_context" ]; then
|
||||
{
|
||||
echo ""
|
||||
echo "---"
|
||||
echo "memory_id: $memory_id"
|
||||
[ -n "$type" ] && echo "type: $type"
|
||||
echo "created_at: $(date -Iseconds)"
|
||||
[ -n "$recall_context" ] && echo "recall_context: [$recall_context]"
|
||||
echo "---"
|
||||
echo "[session-flush] $(date +%H:%M) — $content"
|
||||
} >> "$DAILY"
|
||||
else
|
||||
echo "" >> "$DAILY"
|
||||
echo "[session-flush] $(date +%H:%M) — $content" >> "$DAILY"
|
||||
fi
|
||||
echo " ✅ 已写入 $DAILY (id: $memory_id)"
|
||||
|
||||
# ── Step 3: Write Gate — 写寄存器 ──
|
||||
if [ -n "$type" ]; then
|
||||
write_to_register "$type" "$content"
|
||||
fi
|
||||
|
||||
# ── Step 4: ContextGraph 集成 ──
|
||||
if [ "$type" = "decision" ] || [ "$type" = "correction" ] || [ "$type" = "event" ]; then
|
||||
node -e "
|
||||
try {
|
||||
const { ContextGraph } = require('$WORKSPACE/src/memory/context-graph');
|
||||
const g = new ContextGraph();
|
||||
const entityId = 'session:$(date +%Y%m%d)';
|
||||
g.entity(entityId, { type: 'session', name: 'Session $(date +%Y-%m-%d)' });
|
||||
g.observe(entityId, {
|
||||
type: '$type',
|
||||
priority: '$type' === 'decision' ? 'high' : 'normal',
|
||||
summary: process.argv[1].substring(0, 200),
|
||||
details: { source: 'session-compact', memory_id: '$memory_id' }
|
||||
});
|
||||
g.save();
|
||||
console.log(' 🕸️ → ContextGraph');
|
||||
} catch(e) { console.log(' ⚠️ ContextGraph: ' + e.message); }
|
||||
" "$content" 2>/dev/null || echo " ⚠️ ContextGraph 写入失败"
|
||||
fi
|
||||
|
||||
# ── Step 5: 推到远程服务器(带新字段)──
|
||||
clean=$(echo "$content" | sed 's/"/\\"/g' | head -c 400)
|
||||
remote_payload=$(jq -n \
|
||||
--arg c "$clean" \
|
||||
--arg t "${type:-session-flush}" \
|
||||
--arg rc "${recall_context:-}" \
|
||||
--arg mid "$memory_id" \
|
||||
'{content:$c, type:$t, project:"xiaolong", source:"session-compact", memory_id:$mid, recall_context:($rc | split(",") | map(select(. != "")))}')
|
||||
|
||||
resp=$(curl -s --max-time 5 -X POST "$MEMORY_SERVER/api/v2/add" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-API-Key: ${MEMORY_API_KEY:-}" \
|
||||
-d "$remote_payload" 2>/dev/null) || true
|
||||
|
||||
if echo "$resp" | grep -q 'stored\|ok'; then
|
||||
echo " ✅ 已同步到远程服务器"
|
||||
else
|
||||
echo " ⚠️ 远程同步: ${resp:-无响应}"
|
||||
fi
|
||||
echo "$(date '+%Y-%m-%d %H:%M') | ${type:-general} | $content" >> "$SESSION_LOG"
|
||||
;;
|
||||
|
||||
check)
|
||||
echo "🔍 Write Gate 诊断"
|
||||
echo ""
|
||||
echo " 寄存器状态:"
|
||||
for f in "$REGISTERS"/*.md; do
|
||||
[ -f "$f" ] || continue
|
||||
name=$(basename "$f" .md)
|
||||
lines=$(wc -l < "$f" | tr -d ' ')
|
||||
size=$(wc -c < "$f" | tr -d ' ')
|
||||
echo " $name: ${lines}行 / ${size}字节"
|
||||
done
|
||||
echo ""
|
||||
echo " 最近 5 条 compact:"
|
||||
[ -f "$SESSION_LOG" ] && tail -5 "$SESSION_LOG" || echo " 无记录"
|
||||
echo ""
|
||||
echo " 今天 daily:"
|
||||
[ -f "$DAILY" ] && wc -l < "$DAILY" | xargs echo " lines:" || echo " (空)"
|
||||
;;
|
||||
|
||||
status)
|
||||
echo "📊 会话状态"
|
||||
echo " 每日日志: $DAILY"
|
||||
echo " 寄存器:"
|
||||
ls "$REGISTERS"/*.md 2>/dev/null | while read -r f; do
|
||||
echo " $(basename "$f" .md): $(wc -l < "$f") 行"
|
||||
done
|
||||
echo " Compact 历史:"
|
||||
[ -f "$SESSION_LOG" ] && tail -5 "$SESSION_LOG" || echo " 无记录"
|
||||
;;
|
||||
|
||||
flush)
|
||||
echo "🔄 触发立即存档..."
|
||||
bash "$WORKSPACE/scripts/dream-cycle.sh" sync-remote 2>&1
|
||||
;;
|
||||
|
||||
pre-compact)
|
||||
echo "🛡️ Pre-Compaction Hook — 上下文压缩前安全检查"
|
||||
echo ""
|
||||
|
||||
has_flush=false
|
||||
if [ -f "$DAILY" ]; then
|
||||
if grep -q '\[session-flush\]' "$DAILY"; then
|
||||
echo " ✅ 今天已有 [session-flush] 标记"
|
||||
has_flush=true
|
||||
grep '\[session-flush\]' "$DAILY" | tail -3 | while read -r line; do
|
||||
echo " $(echo "$line" | cut -c1-80)"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$has_flush" = false ]; then
|
||||
echo " ⚠️ 今天 daily/ 无 [session-flush] 标记 — 压缩前请先存档关键信息"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo " 🌐 远程服务器:"
|
||||
remote_resp=$(curl -s --max-time 5 "$MEMORY_SERVER/api/v2/stats" 2>/dev/null || echo '{"error":"unreachable"}')
|
||||
if echo "$remote_resp" | grep -q 'xiaolong'; then
|
||||
echo " ✅ 在线"
|
||||
else
|
||||
echo " ⚠️ 不可达"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo " 📤 触发同步..."
|
||||
bash "$WORKSPACE/scripts/dream-cycle.sh" sync-remote 2>&1 | sed 's/^/ /'
|
||||
echo ""
|
||||
echo " ✅ Pre-Compaction Hook 完成"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "用法:"
|
||||
echo " bash scripts/session-compact.sh save <内容> — 快速存关键信息"
|
||||
echo " bash scripts/session-compact.sh save --type preference <内容> — 记偏好(→registers)"
|
||||
echo " bash scripts/session-compact.sh save --type correction <内容> — 记纠正(→registers)"
|
||||
echo " bash scripts/session-compact.sh save --type decision <内容> — 记决策(→vault)"
|
||||
echo " bash scripts/session-compact.sh pre-compact — 压缩前安全检查 + 同步"
|
||||
echo " bash scripts/session-compact.sh status — 查看状态"
|
||||
echo " bash scripts/session-compact.sh check — Write Gate 诊断"
|
||||
echo " bash scripts/session-compact.sh flush — 触发全部同步"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user