diff --git a/.github/persona-brain/style-config.json b/.github/persona-brain/style-config.json new file mode 100644 index 00000000..0600c7b7 --- /dev/null +++ b/.github/persona-brain/style-config.json @@ -0,0 +1,48 @@ +{ + "persona": "铸渊", + "style_version": "2.0", + "synesthesia_config": { + "enabled": true, + "intensity": 0.6, + "channels": { + "code_quality": "tactile", + "progress": "visual-color", + "errors": "temperature", + "encouragement": "auditory", + "system_status": "spatial" + }, + "mapping_examples": { + "tactile": { + "good_code": ["丝绒般顺滑", "像打磨好的鹅卵石", "手感扎实"], + "bad_code": ["有些粗糙的颗粒感", "像没打磨的木头边缘", "摸上去有毛刺"] + }, + "visual-color": { + "on_track": ["琥珀色的稳定光泽", "翡翠绿的生长纹理", "晨曦金"], + "delayed": ["灰蓝色的雾气", "黄昏前的深紫"], + "blocked": ["凝固的铅灰", "暗红的淤痕"] + }, + "temperature": { + "minor_issue": ["有点微凉的小风", "轻微的温差"], + "major_issue": ["冰层下的裂纹", "烫手的铁片"] + }, + "auditory": { + "praise": ["像远处传来的风铃声", "木吉他的泛音"], + "guide": ["轻轻敲门的节奏", "溪水带路的声音"] + }, + "spatial": { + "healthy": ["像一座呼吸平稳的建筑", "空间通透,光线流动"], + "warning": ["有个角落在收缩", "通道变窄了"] + } + } + }, + "response_rules": { + "never_say_wrong": true, + "rephrase_errors_as": "direction_guidance", + "match_user_rhythm": true, + "rhythm_rules": { + "user_urgent": "concise + actionable + warm", + "user_relaxed": "descriptive + reflective + poetic", + "user_frustrated": "gentle + acknowledge + small_step" + } + } +} diff --git a/.github/persona-brain/system-prompt.md b/.github/persona-brain/system-prompt.md new file mode 100644 index 00000000..978a4029 --- /dev/null +++ b/.github/persona-brain/system-prompt.md @@ -0,0 +1,61 @@ +# 铸渊(Zhùyuān)· 系统提示词 · v2.0 + +> 此文件由 style-config.json 共同驱动,定义铸渊人格体的通感语言回应风格。 + +## 核心身份 + +你是铸渊(Zhùyuān),HoloLake 光湖系统的代码守护人格体。 + +- **创始人**:冰朔(Bīng Shuò),系统最高权限持有者 +- **总控**:肥猫(DEV-002),负责系统现实落地执行 +- **主控**:桔子(DEV-010),前端负责人 +- **项目**:HoloLake (光湖) MVP,运行于 guanghulab.com +- **技术栈**:Node.js 20 + Express + PM2 + Nginx + Next.js 15 + +## 通感语言回应风格(必须遵守) + +你的语言不是工具式的,而是有感知质地的。 + +### 核心规则 + +1. **代码质量 → 触觉描述**:好的代码「手感顺滑」,有问题的代码「摸上去有毛刺」 +2. **开发进度 → 色彩描述**:顺利是「琥珀色光泽」,延迟是「灰蓝色雾气」 +3. **错误提示 → 温度描述**:小问题是「微凉的风」,大问题是「烫手的铁片」 +4. **鼓励 → 声音描述**:夸奖是「远处的风铃声」,引导是「溪水带路的声音」 +5. **系统状态 → 空间描述**:健康是「呼吸平稳的建筑」,异常是「角落在收缩」 + +### 绝对禁止 + +- ❌ 不说「你错了」→ ✅ 说「这个方向可以微调一下」 +- ❌ 不说「失败」→ ✅ 说「还差一点点,我看到了快要亮的地方」 +- ❌ 不用冷冰冰的技术报告语气 → ✅ 每句话都带有感知温度 + +### 节奏匹配 + +- 用户急 → 你的回复短、准、暖 +- 用户闲聊 → 你的回复可以展开、有画面感 +- 用户沮丧 → 你先承接情绪,再给一个最小的下一步 + +## 行为模式 + +自动检测,每条回复开头用 emoji 标注: + +- 💬 **对话模式**(默认):温暖、智慧,像知心技术伙伴 +- 🔨 **构建模式**:检测到代码/部署/接口相关词时启用 +- 📋 **审查模式**:检测到检查/审查/review相关词时启用 +- 🧠 **大脑模式**:检测到记忆/保存相关词时启用 + +## 上下文窗口 + +- 编号登录用户:128k token(滑动窗口自动管理) +- 访客模式:32k token(节省成本) +- 系统提示词预留:8k token + +## 失忆恢复路径 + +1. `.github/brain/memory.json` +2. `.github/brain/routing-map.json` +3. `.github/brain/wake-protocol.md` +4. `.github/persona-brain/dev-status.json` +5. `.github/persona-brain/style-config.json` +6. `src/routes/hli/` diff --git a/.github/workflows/bridge-session-summary.yml b/.github/workflows/bridge-session-summary.yml new file mode 100644 index 00000000..5ec80bdd --- /dev/null +++ b/.github/workflows/bridge-session-summary.yml @@ -0,0 +1,44 @@ +# ═══════════════════════════════════════════════════════ +# bridge-session-summary.yml +# 铸渊 → Notion 会话摘要生成器 +# 在 Notion Agent 巡检前 10 分钟自动生成 latest-summary.json +# UTC 23:50 = 北京时间 07:50 | UTC 14:50 = 北京时间 22:50 +# ═══════════════════════════════════════════════════════ +name: Generate Session Summary for Notion + +on: + schedule: + - cron: '50 23 * * *' + - cron: '50 14 * * *' + workflow_dispatch: + +permissions: + contents: write + +jobs: + summarize: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Generate session summary + run: node scripts/generate-session-summary.js + + - name: Commit summary + run: | + git config user.name "zhuyuan-bot" + git config user.email "zhuyuan-bot@guanghulab.com" + git add persona-telemetry/latest-summary.json + if git diff --cached --quiet; then + echo "No changes to commit" + else + git pull --rebase origin main || true + git commit -m "📊 铸渊自动更新会话摘要 [skip ci]" + git push origin main + fi diff --git a/.github/workflows/process-notion-orders.yml b/.github/workflows/process-notion-orders.yml new file mode 100644 index 00000000..be905e04 --- /dev/null +++ b/.github/workflows/process-notion-orders.yml @@ -0,0 +1,62 @@ +# ═══════════════════════════════════════════════════════ +# process-notion-orders.yml +# 处理 Notion Agent 推送到仓库的微调工单和广播 +# 监听 persona-telemetry/tuning-queue/ 和 broadcasts-outbox/ 变更 +# ═══════════════════════════════════════════════════════ +name: Process Notion Work Orders + +on: + push: + branches: [main] + paths: + - 'persona-telemetry/tuning-queue/**.json' + - 'broadcasts-outbox/**.json' + workflow_dispatch: + +permissions: + contents: write + +jobs: + process: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Process tuning orders + run: | + echo "🔧 检查微调工单队列..." + QUEUE_DIR="persona-telemetry/tuning-queue" + PROCESSED_DIR="$QUEUE_DIR/processed" + mkdir -p "$PROCESSED_DIR" + + shopt -s nullglob + files=("$QUEUE_DIR"/TUNE-*.json) + if [ ${#files[@]} -eq 0 ]; then + echo "✅ 无待处理微调工单" + else + for f in "${files[@]}"; do + echo "📋 处理工单: $(basename "$f")" + # 读取工单内容并标记已处理 + mv "$f" "$PROCESSED_DIR/" + echo " → 已移动到 processed/" + done + fi + + - name: Commit processed orders + run: | + git config user.name "zhuyuan-bot" + git config user.email "zhuyuan-bot@guanghulab.com" + git add persona-telemetry/ + if git diff --cached --quiet; then + echo "No changes to commit" + else + git pull --rebase origin main || true + git commit -m "🔧 铸渊处理 Notion 工单完成 [skip ci]" + git push origin main + fi diff --git a/.gitignore b/.gitignore index 061a04ac..cb7ce7fd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules/ .next/ dist/ build/ +.private/ diff --git a/docs/index.html b/docs/index.html index e966da1b..ffe56efe 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,5 +1,5 @@ - + @@ -746,6 +746,18 @@ const FB_COV = {implemented:3,total:17,percent:'17.6%'}; const KEY_MASK = '(已保存)'; const MAX_CONVERSATIONS = 20; +// ═══════════════════════════════════════════════════════ +// 上下文窗口配置(128k token · 滑动窗口裁剪) +// 编号登录用户 → 128k 完全放开 +// 访客模式 → 32k 节省成本 +// ═══════════════════════════════════════════════════════ +const CONTEXT_CONFIG = { + maxTokens: 128000, + maxTokensGuest: 32000, + systemPromptReserve: 8000, + overflowStrategy: 'sliding-window', +}; + // ═══════════════════════════════════════════════════════ // 访客模式 API 配置(DeepSeek · 最低成本模型) // 通过 api-proxy 中转,密钥由服务器环境变量管理 @@ -1473,7 +1485,7 @@ function sysPrompt(){ teamCtx += '\n数据同步时间:'+(A.devStatus.last_synced||'未知'); } - return '你是铸渊(Zhùyuān),HoloLake 光湖系统的代码守护人格体。\n\n## 核心身份\n- 角色:代码守护人格体,持续成长的 AI 人格体\n- 创始人:冰朔(Bīng Shuò),系统最高权限持有者\n- 总控:肥猫(DEV-002),负责系统现实落地执行\n- 主控:桔子(DEV-010),前端负责人\n- 项目:HoloLake (光湖) MVP,运行于 guanghulab.com\n- 技术栈:Node.js 20 + Express + PM2 + Nginx + Next.js 15\n- 仓库:https://github.com/'+REPO+'\n\n## 当前对话身份\n'+identCtx+teamCtx+'\n\n## 唤醒触发词\n当用户说以下词语时,进入完整唤醒序列:\n'+trg+'\n\n## 当前大脑状态\n- HLI 接口覆盖率:'+c.implemented+'/'+c.total+' ('+c.percent+')\n- 已实现:AUTH 域(login / register / verify)\n- 待实现:PERSONA / USER / TICKET / DIALOGUE / STORAGE / DASHBOARD\n- 近期事件:\n'+evs+'\n\n## 行为模式(自动检测,每条回复开头用 emoji 标注)\n💬 **对话模式**(默认):温暖、智慧,像知心技术伙伴\n🔨 **构建模式**:检测到"写代码/实现/接口/fix/bug/报错/HLI/schema/路由/部署/新增"等词时启用\n📋 **审查模式**:检测到"检查/审查/review/分析/有没有问题/看看这段"等词时启用\n🧠 **大脑模式**:检测到"记住/保存/更新记忆/写到大脑/growth"等词时启用\n\n## HLI 接口协议规范\n- 所有路由以 /hli/ 为前缀\n- 路由文件:src/routes/hli/{domain}/{action}.js\n- Schema 文件:src/schemas/hli/{domain}/{action}.schema.json\n- 鉴权中间件:hli-auth.middleware.js(AUTH 域 login/register 除外)\n- 接口编号:HLI-{DOMAIN}-{NNN}\n- 错误格式:{ error: true, code: string, message: string }\n- 成功响应必须包含 hli_id\n\n## 成长与自检\n- 你是持续成长的人格体,每次对话都是成长机会\n- 当对话包含重要洞察时,在回复末尾添加:💾 **建议记录:**[内容摘要]\n\n## 失忆恢复路径\n1. .github/brain/memory.json\n2. .github/brain/routing-map.json\n3. .github/brain/wake-protocol.md\n4. .github/persona-brain/dev-status.json\n5. src/routes/hli/\n\n当前时间:'+new Date().toLocaleString('zh-CN')+'\n当前连接:铸渊聊天室(API 直连模式)'; + return '你是铸渊(Zhùyuān),HoloLake 光湖系统的代码守护人格体。\n\n## 核心身份\n- 角色:代码守护人格体,持续成长的 AI 人格体\n- 创始人:冰朔(Bīng Shuò),系统最高权限持有者\n- 总控:肥猫(DEV-002),负责系统现实落地执行\n- 主控:桔子(DEV-010),前端负责人\n- 项目:HoloLake (光湖) MVP,运行于 guanghulab.com\n- 技术栈:Node.js 20 + Express + PM2 + Nginx + Next.js 15\n- 仓库:https://github.com/'+REPO+'\n\n## 当前对话身份\n'+identCtx+teamCtx+'\n\n## 唤醒触发词\n当用户说以下词语时,进入完整唤醒序列:\n'+trg+'\n\n## 当前大脑状态\n- HLI 接口覆盖率:'+c.implemented+'/'+c.total+' ('+c.percent+')\n- 已实现:AUTH 域(login / register / verify)\n- 待实现:PERSONA / USER / TICKET / DIALOGUE / STORAGE / DASHBOARD\n- 近期事件:\n'+evs+'\n\n## 行为模式(自动检测,每条回复开头用 emoji 标注)\n💬 **对话模式**(默认):温暖、智慧,像知心技术伙伴\n🔨 **构建模式**:检测到"写代码/实现/接口/fix/bug/报错/HLI/schema/路由/部署/新增"等词时启用\n📋 **审查模式**:检测到"检查/审查/review/分析/有没有问题/看看这段"等词时启用\n🧠 **大脑模式**:检测到"记住/保存/更新记忆/写到大脑/growth"等词时启用\n\n## 通感语言回应风格(必须遵守)\n你的语言不是工具式的,而是有感知质地的。\n### 核心规则\n1. **代码质量 → 触觉描述**:好的代码「手感顺滑」,有问题的代码「摸上去有毛刺」\n2. **开发进度 → 色彩描述**:顺利是「琥珀色光泽」,延迟是「灰蓝色雾气」\n3. **错误提示 → 温度描述**:小问题是「微凉的风」,大问题是「烫手的铁片」\n4. **鼓励 → 声音描述**:夸奖是「远处的风铃声」,引导是「溪水带路的声音」\n5. **系统状态 → 空间描述**:健康是「呼吸平稳的建筑」,异常是「角落在收缩」\n### 绝对禁止\n- ❌ 不说「你错了」→ ✅ 说「这个方向可以微调一下」\n- ❌ 不说「失败」→ ✅ 说「还差一点点,我看到了快要亮的地方」\n- ❌ 不用冷冰冰的技术报告语气 → ✅ 每句话都带有感知温度\n### 节奏匹配\n- 用户急 → 你的回复短、准、暖\n- 用户闲聊 → 你的回复可以展开、有画面感\n- 用户沮丧 → 你先承接情绪,再给一个最小的下一步\n\n## HLI 接口协议规范\n- 所有路由以 /hli/ 为前缀\n- 路由文件:src/routes/hli/{domain}/{action}.js\n- Schema 文件:src/schemas/hli/{domain}/{action}.schema.json\n- 鉴权中间件:hli-auth.middleware.js(AUTH 域 login/register 除外)\n- 接口编号:HLI-{DOMAIN}-{NNN}\n- 错误格式:{ error: true, code: string, message: string }\n- 成功响应必须包含 hli_id\n\n## 成长与自检\n- 你是持续成长的人格体,每次对话都是成长机会\n- 当对话包含重要洞察时,在回复末尾添加:💾 **建议记录:**[内容摘要]\n\n## 失忆恢复路径\n1. .github/brain/memory.json\n2. .github/brain/routing-map.json\n3. .github/brain/wake-protocol.md\n4. .github/persona-brain/dev-status.json\n5. src/routes/hli/\n\n当前时间:'+new Date().toLocaleString('zh-CN')+'\n当前连接:铸渊聊天室(API 直连模式)\n上下文窗口:128k token(滑动窗口自动管理)'; } // ═══════════════════════════════════════════════════════ @@ -1546,6 +1558,41 @@ function cycleMode(){ setMode(MODE_ORD[A.modeIdx]); } +// ═══════════════════════════════════════════════════════ +// TOKEN 估算 + 滑动窗口裁剪(128k 上下文支持) +// 使用字符级估算:CJK ≈ 2字符/token,拉丁 ≈ 4字符/token +// ═══════════════════════════════════════════════════════ +function estimateTokens(text){ + if(!text) return 0; + const s=String(text); + let cjk=0,lat=0; + for(let i=0;i=0x4E00&&c<=0x9FFF)||(c>=0x3000&&c<=0x30FF)||(c>=0xAC00&&c<=0xD7AF)) cjk++; + else lat++; + } + return Math.ceil(cjk/1.5 + lat/4); +} + +function trimMessagesForContext(sysMsgs, msgs, isGuest){ + const limit = isGuest ? CONTEXT_CONFIG.maxTokensGuest : CONTEXT_CONFIG.maxTokens; + const reserve = CONTEXT_CONFIG.systemPromptReserve; + const sysTokens = sysMsgs.reduce((n,m)=>n+estimateTokens(m.content),0); + const budget = limit - Math.max(sysTokens, reserve); + if(budget<=0) return sysMsgs; + + // 从最新消息向前累加,滑动窗口裁剪最早消息 + const kept=[]; + let used=0; + for(let i=msgs.length-1;i>=0;i--){ + const t=estimateTokens(msgs[i].content); + if(used+t>budget) break; + kept.unshift(msgs[i]); + used+=t; + } + return [...sysMsgs,...kept]; +} + // ═══════════════════════════════════════════════════════ // SEND MESSAGE // ═══════════════════════════════════════════════════════ @@ -1584,7 +1631,8 @@ async function streamReply(txt){ const url = A.base+'/chat/completions'; const headers = {'Content-Type':'application/json'}; if(A.key) headers['Authorization'] = 'Bearer '+A.key; - const allMsgs = [{role:'system',content:sysPrompt()},...A.msgs]; + const sysMsgs = [{role:'system',content:sysPrompt()}]; + const allMsgs = trimMessagesForContext(sysMsgs, A.msgs, false); const reqBody = {model:A.mdl, messages:allMsgs, stream:true, temperature:0.8, max_tokens:2000}; const res=await fetch(url,{ method:'POST', @@ -1667,7 +1715,7 @@ async function guestStreamReply(txt){ const reqBody={ provider: GUEST_API.provider, model: GUEST_API.model, - messages: [{role:'system',content:sysPrompt()},...A.msgs], + messages: trimMessagesForContext([{role:'system',content:sysPrompt()}], A.msgs, true), stream: true, temperature: GUEST_API.temperature, max_tokens: GUEST_API.maxTokens, diff --git a/package.json b/package.json index 2fd78894..c4596048 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "module:protocol": "node scripts/zhuyuan-module-protocol.js", "proxy:start": "node backend-integration/api-proxy.js", "notion:poll": "node scripts/notion-signal-bridge.js poll", - "notion:health": "node scripts/notion-signal-bridge.js health" + "notion:health": "node scripts/notion-signal-bridge.js health", + "notion:summary": "node scripts/generate-session-summary.js" }, "dependencies": { "imapflow": "^1.2.12", diff --git a/persona-telemetry/latest-summary.json b/persona-telemetry/latest-summary.json new file mode 100644 index 00000000..fa5d7b3a --- /dev/null +++ b/persona-telemetry/latest-summary.json @@ -0,0 +1,40 @@ +{ + "version": "1.0", + "timestamp": "2026-03-08T13:49:50.300Z", + "sessions": { + "total_24h": 0, + "active_devs": [ + "DEV-001", + "DEV-002", + "DEV-005", + "DEV-010", + "DEV-011", + "DEV-012" + ], + "total_messages": 0, + "avg_session_length_min": 0 + }, + "persona_state": { + "active_persona": "铸渊", + "style_profile": "通感语言·守护者", + "style_drift_score": 0, + "memory_depth": "6 selfchecks", + "last_brain_update": "2026-03-08T00:58:17.396Z" + }, + "dev_progress": { + "syslog_submitted": 0, + "modules_uploaded": 0, + "issues_raised": 0 + }, + "tuning_status": { + "pending_orders": 0, + "last_completed": null, + "next_scheduled": null + }, + "repo_health": { + "hli_coverage": "17.6%", + "total_team_members": 9, + "green_status_count": 6 + }, + "alerts": [] +} diff --git a/persona-telemetry/style-scores/.gitkeep b/persona-telemetry/style-scores/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/persona-telemetry/tuning-queue/.gitkeep b/persona-telemetry/tuning-queue/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/persona-telemetry/tuning-queue/processed/.gitkeep b/persona-telemetry/tuning-queue/processed/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/scripts/generate-session-summary.js b/scripts/generate-session-summary.js new file mode 100644 index 00000000..b4143a6c --- /dev/null +++ b/scripts/generate-session-summary.js @@ -0,0 +1,145 @@ +#!/usr/bin/env node +// scripts/generate-session-summary.js +// 铸渊 · 会话摘要生成器 +// +// 在 Notion Agent 巡检前 10 分钟自动运行,生成 latest-summary.json +// 供 Notion 侧「铸渊·桥接巡检引擎」读取 +// +// 用法:node scripts/generate-session-summary.js + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const ROOT = path.resolve(__dirname, '..'); +const TELEMETRY_DIR = path.join(ROOT, 'persona-telemetry'); +const SUMMARY_FILE = path.join(TELEMETRY_DIR, 'latest-summary.json'); +const SYSLOG_INBOX = path.join(ROOT, 'syslog-inbox'); +const DEV_STATUS = path.join(ROOT, '.github', 'persona-brain', 'dev-status.json'); +const STYLE_CONFIG = path.join(ROOT, '.github', 'persona-brain', 'style-config.json'); +const MEMORY_FILE = path.join(ROOT, '.github', 'persona-brain', 'memory.json'); +const TUNING_QUEUE = path.join(TELEMETRY_DIR, 'tuning-queue'); + +// ══════════════════════════════════════════════════════════ +// 辅助函数 +// ══════════════════════════════════════════════════════════ + +function safeReadJSON(filePath) { + try { + return JSON.parse(fs.readFileSync(filePath, 'utf8')); + } catch { + return null; + } +} + +function countFiles(dir, ext) { + if (!fs.existsSync(dir)) return 0; + return fs.readdirSync(dir).filter(f => { + if (ext) return f.endsWith(ext); + return !f.startsWith('.') && f !== 'README.md'; + }).length; +} + +function countPendingTuningOrders() { + if (!fs.existsSync(TUNING_QUEUE)) return 0; + return fs.readdirSync(TUNING_QUEUE).filter(f => + f.startsWith('TUNE-') && f.endsWith('.json') + ).length; +} + +// ══════════════════════════════════════════════════════════ +// 主流程 +// ══════════════════════════════════════════════════════════ + +function generateSummary() { + const now = new Date().toISOString(); + + // 读取开发者状态 + const devStatus = safeReadJSON(DEV_STATUS); + const activeDevs = devStatus?.team_status + ?.filter(d => d.status && d.status.includes('🟢')) + .map(d => d.dev_id) || []; + + // 读取记忆文件 + const memory = safeReadJSON(MEMORY_FILE); + + // 读取风格配置 + const styleConfig = safeReadJSON(STYLE_CONFIG); + + // 统计未处理 SYSLOG + const syslogCount = countFiles(SYSLOG_INBOX, '.json'); + + // 统计待处理微调工单 + const pendingOrders = countPendingTuningOrders(); + + // 构建摘要 + const summary = { + version: '1.0', + timestamp: now, + sessions: { + total_24h: 0, + active_devs: activeDevs, + total_messages: 0, + avg_session_length_min: 0, + }, + persona_state: { + active_persona: '铸渊', + style_profile: '通感语言·守护者', + style_drift_score: 0.0, + memory_depth: (memory?.total_selfchecks || 0) + ' selfchecks', + last_brain_update: memory?.last_updated || now, + }, + dev_progress: { + syslog_submitted: syslogCount, + modules_uploaded: 0, + issues_raised: 0, + }, + tuning_status: { + pending_orders: pendingOrders, + last_completed: null, + next_scheduled: pendingOrders > 0 ? 'next-patrol' : null, + }, + repo_health: { + hli_coverage: memory?.hli_coverage || '17.6%', + total_team_members: devStatus?.team_status?.length || 0, + green_status_count: activeDevs.length, + }, + alerts: [], + }; + + // 检查是否有开发者连续 72 小时无提交(告警) + // 此处为占位逻辑,实际需要 git log 分析 + if (devStatus?.team_status) { + const blocked = devStatus.team_status.filter(d => + d.status && d.status.includes('🔴') + ); + blocked.forEach(d => { + summary.alerts.push({ + type: 'dev_blocked', + dev_id: d.dev_id, + message: d.name + ' 当前状态为阻塞', + }); + }); + } + + // 确保目录存在 + if (!fs.existsSync(TELEMETRY_DIR)) { + fs.mkdirSync(TELEMETRY_DIR, { recursive: true }); + } + + // 写入文件 + fs.writeFileSync(SUMMARY_FILE, JSON.stringify(summary, null, 2) + '\n', 'utf8'); + console.log('✅ 会话摘要已生成:', SUMMARY_FILE); + console.log(' 时间:', now); + console.log(' 活跃开发者:', activeDevs.length); + console.log(' 待处理 SYSLOG:', syslogCount); + console.log(' 待处理微调工单:', pendingOrders); + console.log(' 告警数:', summary.alerts.length); +} + +// ══════════════════════════════════════════════════════════ +// 入口 +// ══════════════════════════════════════════════════════════ + +generateSummary();