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..c559d7c9
--- /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 * * *' # 07:50 Beijing Time
+ - cron: '50 14 * * *' # 22:50 Beijing Time
+ 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/deploy-to-server.yml b/.github/workflows/deploy-to-server.yml
index dd8ef35f..5426f0a0 100644
--- a/.github/workflows/deploy-to-server.yml
+++ b/.github/workflows/deploy-to-server.yml
@@ -210,6 +210,19 @@ jobs:
exit 0
fi
+ # 部署 API 代理服务(AI 聊天代理,端口 3721)
+ if [ -f '${{ secrets.DEPLOY_PATH }}/backend-integration/api-proxy.js' ]; then
+ echo '📦 安装 API 代理依赖...'
+ cd '${{ secrets.DEPLOY_PATH }}/backend-integration'
+ npm install --production 2>/dev/null || echo '⚠️ api-proxy npm install 失败(可能无 package.json,继续)'
+ echo '🔄 重启 API 代理服务...'
+ export YUNWU_API_KEY='${{ secrets.YUNWU_API_KEY }}'
+ export DEEPSEEK_API_KEY='${{ secrets.YUNWU_API_KEY }}'
+ pm2 delete guanghulab-proxy 2>/dev/null || true
+ pm2 start api-proxy.js --name guanghulab-proxy 2>/dev/null || \
+ echo '⚠️ API 代理 pm2 启动失败'
+ fi
+
# 部署 backend 服务(Express API,端口 3000)
if [ -f '${{ secrets.DEPLOY_PATH }}/backend/server.js' ]; then
echo '📦 安装 backend 依赖...'
@@ -287,7 +300,37 @@ jobs:
printf '%s\n' \
'# guanghulab 反向代理(由 CD 工作流自动生成)' \
'' \
- '# API 反向代理 → Express 后端端口 3000' \
+ '# AI 聊天 API 代理 → api-proxy.js 端口 3721(SSE 流式支持)' \
+ 'location /api/chat {' \
+ ' proxy_pass http://127.0.0.1:3721/api/chat;' \
+ ' proxy_http_version 1.1;' \
+ ' proxy_set_header Host \$host;' \
+ ' proxy_set_header X-Real-IP \$remote_addr;' \
+ ' proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;' \
+ ' proxy_set_header X-Forwarded-Proto \$scheme;' \
+ ' proxy_set_header Connection "";' \
+ ' proxy_buffering off;' \
+ ' proxy_cache off;' \
+ ' chunked_transfer_encoding on;' \
+ ' proxy_read_timeout 90s;' \
+ ' proxy_send_timeout 60s;' \
+ '}' \
+ '' \
+ 'location /api/models {' \
+ ' proxy_pass http://127.0.0.1:3721/api/models;' \
+ ' proxy_http_version 1.1;' \
+ ' proxy_set_header Host \$host;' \
+ ' proxy_set_header X-Real-IP \$remote_addr;' \
+ '}' \
+ '' \
+ 'location /api/health {' \
+ ' proxy_pass http://127.0.0.1:3721/api/health;' \
+ ' proxy_http_version 1.1;' \
+ ' proxy_set_header Host \$host;' \
+ ' proxy_set_header X-Real-IP \$remote_addr;' \
+ '}' \
+ '' \
+ '# 其他 API → Express 后端端口 3000' \
'location /api/ {' \
' proxy_pass http://127.0.0.1:3000/api/;' \
' proxy_http_version 1.1;' \
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/backend/routes/developers.js b/backend/routes/developers.js
new file mode 100644
index 00000000..68764ced
--- /dev/null
+++ b/backend/routes/developers.js
@@ -0,0 +1,173 @@
+const express = require('express');
+const axios = require('axios');
+const router = express.Router();
+
+const NOTION_TOKEN = process.env.NOTION_TOKEN;
+const DEVELOPERS_DB_ID = process.env.DEVELOPERS_DB_ID || '';
+const NOTION_VERSION = '2022-06-28';
+const BASE_URL = 'https://api.notion.com/v1';
+
+const headers = () => ({
+ 'Authorization': 'Bearer ' + NOTION_TOKEN,
+ 'Content-Type': 'application/json',
+ 'Notion-Version': NOTION_VERSION
+});
+
+// Validate DEV-XXX format
+const DEV_ID_RE = /^DEV-\d{3,}$/;
+
+// Notion database property names (match your Notion schema)
+const PROP = {
+ DEV_ID: 'DEV编号',
+ DEV_ID_ALT: 'DEV ID',
+ TITLE: '标题',
+ NAME: '姓名',
+ NAME_ALT: '名称',
+ ROLE: '角色',
+ JOB_TITLE: '职位',
+ JOB_TITLE_ALT: '岗位',
+ EMAIL: '邮箱',
+ GITHUB: 'GitHub',
+ STATUS: '状态',
+};
+
+// Build Notion filter query for developer lookup by DEV ID
+function devIdFilter(devId) {
+ return {
+ or: [
+ { property: PROP.DEV_ID, title: { equals: devId } },
+ { property: PROP.DEV_ID_ALT, title: { equals: devId } },
+ { property: PROP.TITLE, title: { equals: devId } }
+ ]
+ };
+}
+
+// Health check
+router.get('/test', (req, res) => {
+ res.json({
+ status: 'ok',
+ message: '开发者路由正常',
+ notion_configured: !!NOTION_TOKEN,
+ db_configured: !!DEVELOPERS_DB_ID
+ });
+});
+
+// Extract developer info from a Notion page result
+function extractDevInfo(page) {
+ const props = page.properties || {};
+ const getText = (prop) => {
+ if (!prop) return '';
+ if (prop.title) return prop.title.map(t => t.plain_text).join('');
+ if (prop.rich_text) return prop.rich_text.map(t => t.plain_text).join('');
+ if (prop.select) return prop.select.name;
+ if (prop.email) return prop.email || '';
+ return '';
+ };
+
+ return {
+ id: page.id,
+ devId: getText(props[PROP.DEV_ID] || props[PROP.DEV_ID_ALT] || props[PROP.TITLE]),
+ name: getText(props[PROP.NAME] || props[PROP.NAME_ALT]),
+ role: getText(props[PROP.ROLE]),
+ title: getText(props[PROP.JOB_TITLE] || props[PROP.JOB_TITLE_ALT]),
+ email: getText(props[PROP.EMAIL]),
+ github: getText(props[PROP.GITHUB]),
+ status: getText(props[PROP.STATUS]),
+ notionUrl: page.url || ''
+ };
+}
+
+// GET /api/v1/developers/:devId — Look up developer by DEV-XXX ID from Notion
+router.get('/:devId', async (req, res) => {
+ const devId = (req.params.devId || '').trim().toUpperCase();
+
+ if (!DEV_ID_RE.test(devId)) {
+ return res.status(400).json({ error: '开发者编号格式不正确,请使用 DEV-XXX 格式' });
+ }
+
+ if (!NOTION_TOKEN) {
+ return res.status(503).json({ error: 'Notion API 未配置', devId: devId, fallback: true });
+ }
+
+ if (!DEVELOPERS_DB_ID) {
+ return res.status(503).json({ error: '开发者数据库未配置', devId: devId, fallback: true });
+ }
+
+ try {
+ const response = await axios.post(
+ BASE_URL + '/databases/' + DEVELOPERS_DB_ID + '/query',
+ { filter: devIdFilter(devId), page_size: 1 },
+ { headers: headers() }
+ );
+
+ const results = response.data.results || [];
+ if (results.length > 0) {
+ const dev = extractDevInfo(results[0]);
+ return res.json({ found: true, developer: dev });
+ }
+
+ return res.json({ found: false, devId: devId, message: '未在 Notion 中找到该开发者,将使用默认配置' });
+ } catch (err) {
+ const errStatus = err.response ? err.response.status : 500;
+ const detail = err.response ? err.response.data : null;
+ return res.status(errStatus >= 400 && errStatus < 600 ? errStatus : 500).json({
+ error: '查询 Notion 失败: ' + err.message,
+ devId: devId,
+ fallback: true,
+ detail: detail
+ });
+ }
+});
+
+// POST /api/v1/developers — Register a new developer in Notion
+router.post('/', async (req, res) => {
+ const { devId, name } = req.body || {};
+
+ if (!devId || !DEV_ID_RE.test(devId)) {
+ return res.status(400).json({ error: '开发者编号格式不正确' });
+ }
+
+ if (!NOTION_TOKEN || !DEVELOPERS_DB_ID) {
+ return res.status(503).json({ error: 'Notion 未配置', devId: devId, fallback: true });
+ }
+
+ try {
+ // Check if already exists
+ const checkResp = await axios.post(
+ BASE_URL + '/databases/' + DEVELOPERS_DB_ID + '/query',
+ { filter: devIdFilter(devId), page_size: 1 },
+ { headers: headers() }
+ );
+
+ if (checkResp.data.results && checkResp.data.results.length > 0) {
+ return res.json({ created: false, message: '开发者已存在', developer: extractDevInfo(checkResp.data.results[0]) });
+ }
+
+ // Create new developer page
+ const newPage = await axios.post(
+ BASE_URL + '/pages',
+ {
+ parent: { database_id: DEVELOPERS_DB_ID },
+ properties: {
+ [PROP.TITLE]: { title: [{ text: { content: devId } }] },
+ [PROP.NAME]: { rich_text: [{ text: { content: name || devId } }] },
+ [PROP.ROLE]: { select: { name: '开发者' } },
+ [PROP.STATUS]: { select: { name: '活跃' } }
+ }
+ },
+ { headers: headers() }
+ );
+
+ return res.json({ created: true, message: '开发者已自动注册', developer: extractDevInfo(newPage.data) });
+ } catch (err) {
+ const detail = err.response ? err.response.data : null;
+ return res.status(500).json({
+ error: '注册失败: ' + err.message,
+ devId: devId,
+ fallback: true,
+ detail: detail
+ });
+ }
+});
+
+module.exports = router;
diff --git a/backend/server.js b/backend/server.js
index 4ba0248e..251eb6af 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -11,12 +11,14 @@ const notionRoutes = require('./routes/notion');
const feishuRoutes = require('./routes/feishu');
const routerRoutes = require('./routes/router');
const coldstartRoutes = require('./routes/coldstart');
+const developersRoutes = require('./routes/developers');
const hliRoutes = require('../src/routes/hli');
app.use('/notion', notionRoutes);
app.use('/feishu', feishuRoutes);
app.use('/router', routerRoutes);
app.use('/api/coldstart', coldstartRoutes);
+app.use('/api/v1/developers', developersRoutes);
app.use('/hli', hliRoutes);
app.get('/', (req, res) => {
@@ -24,7 +26,7 @@ app.get('/', (req, res) => {
status: 'ok',
message: 'HoloLake 后端服务运行中',
version: '0.2.0',
- routes: ['/notion/test', '/feishu/test', '/router/test', '/router/chat', '/api/coldstart', '/hli/test']
+ routes: ['/notion/test', '/feishu/test', '/router/test', '/router/chat', '/api/coldstart', '/api/v1/developers/test', '/hli/test']
});
});
diff --git a/docs/index.html b/docs/index.html
index e966da1b..a3c36efe 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,5 +1,5 @@
-
+
@@ -339,12 +339,47 @@ footer{padding:12px 18px 16px;padding-bottom:max(16px,env(safe-area-inset-bottom
HoloLake · 铸渊(Zhùyuān)· 代码守护人格体
-
-
+
+
+
+
+
+
+
+
+
🌀
+ 光湖团队成员专属入口。
+ 选择你的开发者编号,系统自动分配对应权限。
+
✅ 无需 API 密钥 · 128k 完整上下文 · 服务器端代理
+
+
+
+
+
+
+
+
+ 输入你的开发者编号(格式:DEV-XXX),系统将自动录入
+
+
+
-
+
👤
无需 API 密钥,使用 DeepSeek 模型体验铸渊助手。
@@ -353,7 +388,7 @@ footer{padding:12px 18px 16px;padding-bottom:max(16px,env(safe-area-inset-bottom
-
+
🔒 API 密钥仅本次会话有效,关闭标签页即自动清除
@@ -614,22 +649,22 @@ footer{padding:12px 18px 16px;padding-bottom:max(16px,env(safe-area-inset-bottom
🚀 怎么开始用
- 打开链接 https://qinfendebingshuo.github.io/guanghulab/
- - 选择「👤 访客模式」直接体验,或「🔑 编号登录」开发者身份登录
- - 编号登录:选择你的身份,输入 API 端点 和 API 密钥,点「🔍 检测模型」
- - 系统自动检测可用模型列表,选择你要用的模型
- - 点「开始对话」,铸渊会针对你的身份打招呼
+ - 选择「🏠 团队登录」选择你的开发者编号,无需 API 密钥
+ - 系统自动使用服务器端 API 代理,128k 完整上下文
+ - 点「进入铸渊对话」,铸渊会针对你的身份打招呼
+ - 也可用「👤 访客模式」体验,或「🔧 自定义 API」使用自己的密钥
-
🔑 从哪里获取 API Key?
+
🏠 团队登录说明
-
推荐用云雾 AI(团队共用)
-
找冰朔或肥猫获取团队 Key 和端点地址,输入后点「🔍 检测模型」即可使用。
+
团队成员(推荐)
+
选择「🏠 团队登录」→ 选择你的开发者编号 → 直接进入对话。无需 API 密钥,系统使用服务器端代理。
-
没有 Key?用访客模式
-
登录页选择「👤 访客模式」进入演示,可查看团队进度面板(🦁 指挥台),AI 回答功能受限。
+
没有开发者编号?用访客模式
+
登录页选择「👤 访客模式」进入体验,可查看团队进度面板(🦁 指挥台),AI 回答功能受限。
@@ -722,6 +757,9 @@ const ROLE_MAP = {
'Awen': {role:'dev', title:'通知中心开发', emoji:'💻', badgeCls:'rb-dev', devId:'DEV-012'},
};
+// Custom dev ID format validation (DEV-001, DEV-013, etc.)
+const DEV_ID_RE = /^DEV-\d{3,}$/;
+
// Known API endpoints for fallback auto-detect (when user doesn't provide endpoint)
const KNOWN_ENDPOINTS = [
{label:'云雾 AI', base:'https://api.yunwu.ai/v1'},
@@ -746,6 +784,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 中转,密钥由服务器环境变量管理
@@ -760,6 +810,19 @@ const GUEST_API = {
rateLimit: { maxPerMin: 6, count: 0, resetAt: 0 },
};
+// ═══════════════════════════════════════════════════════
+// 团队模式 API 配置(服务器端代理 · 无需用户提供 API 密钥)
+// 通过 api-proxy 中转,密钥由服务器环境变量 YUNWU_API_KEY 管理
+// 团队成员享有完整 128k 上下文 + 更高 token 限制
+// ═══════════════════════════════════════════════════════
+const TEAM_API = {
+ proxyUrl: '/api/chat',
+ model: 'deepseek-chat',
+ provider: 'yunwu',
+ maxTokens: 2000,
+ temperature: 0.8,
+};
+
const FB_BRAIN = {
identity:'铸渊(Zhùyuān)· GitHub 代码守护人格体',
wake_triggers:['我是冰朔','冰朔','我是妈妈','唤醒铸渊','铸渊,醒来'],
@@ -776,6 +839,7 @@ const A = {
mdl: ls('zy_mdl')||'',
prov: 'custom',
demo: false,
+ teamMode: ls('zy_teammode')==='1',
brain: null,
routing: null,
devStatus: null,
@@ -1195,11 +1259,15 @@ function initSetupUI(){
function switchLoginMode(mode){
document.querySelectorAll('.login-tab').forEach(function(t){t.classList.remove('active');});
document.querySelectorAll('.login-mode').forEach(function(m){m.classList.remove('active');});
- if(mode==='guest'){
- document.querySelector('.login-tab:first-child').classList.add('active');
+ var tabs = document.querySelectorAll('.login-tab');
+ if(mode==='team'){
+ tabs[0].classList.add('active');
+ document.getElementById('login-team').classList.add('active');
+ } else if(mode==='guest'){
+ tabs[1].classList.add('active');
document.getElementById('login-guest').classList.add('active');
} else {
- document.querySelector('.login-tab:last-child').classList.add('active');
+ tabs[2].classList.add('active');
document.getElementById('login-dev').classList.add('active');
}
}
@@ -1304,12 +1372,147 @@ function doSetup(){
}
function doDemo(){
- A.demo=true; A.key=''; A.prov='custom';
+ A.demo=true; A.teamMode=false; A.key=''; A.prov='custom';
A.mdl=GUEST_API.model;
+ lss('zy_teammode','0');
setIdentity('', '');
showApp();
}
+function onTeamSelectChange(){
+ var sel = document.getElementById('tuid').value;
+ var customBox = document.getElementById('team-custom-input');
+ if(sel==='__custom__'){
+ customBox.style.display='';
+ document.getElementById('tcustom-id').value='';
+ document.getElementById('tcustom-id').focus();
+ } else {
+ customBox.style.display='none';
+ }
+ updateTeamIdPreview();
+}
+
+function updateTeamIdPreview(){
+ var sel = document.getElementById('tuid').value;
+ var el = document.getElementById('team-id-preview');
+ if(!el) return;
+
+ // Custom dev ID input mode
+ if(sel==='__custom__'){
+ var raw = (document.getElementById('tcustom-id').value||'').trim().toUpperCase();
+ if(!raw){
+ el.innerHTML = '
'
+ + '✏️ 请输入你的开发者编号(格式:DEV-XXX)'
+ + '
';
+ return;
+ }
+ // Validate format
+ if(DEV_ID_RE.test(raw)){
+ el.innerHTML = '
'
+ + '💻 '+esc(raw)+' · 自定义开发者'
+ + '
✅ 使用服务器端 API 代理 · 128k 上下文 · 首次登录将自动注册'
+ + '
';
+ } else {
+ el.innerHTML = '
'
+ + '⚠️ 编号格式不正确,请使用 DEV-XXX 格式(如 DEV-013)'
+ + '
';
+ }
+ return;
+ }
+
+ // Normal dropdown selection mode
+ if(!sel){ el.innerHTML=''; return; }
+ var meta = ROLE_MAP[sel];
+ if(meta){
+ el.innerHTML = '
'
+ + meta.emoji+' '+esc(sel)+' · '+meta.title
+ + (meta.devId ? ' · '+meta.devId+'' : '')
+ + '
✅ 使用服务器端 API 代理 · 128k 上下文 · 无需密钥'
+ + '
';
+ } else {
+ el.innerHTML = '';
+ }
+}
+
+function doTeamLogin(){
+ var sel = document.getElementById('tuid').value;
+ var un = sel;
+
+ // Handle custom dev ID
+ if(sel==='__custom__'){
+ var raw = (document.getElementById('tcustom-id').value||'').trim().toUpperCase();
+ if(!raw){
+ alert('请输入你的开发者编号(格式:DEV-XXX)');
+ return;
+ }
+ if(!DEV_ID_RE.test(raw)){
+ alert('开发者编号格式不正确,请使用 DEV-XXX 格式(如 DEV-013)');
+ return;
+ }
+ un = raw;
+ }
+
+ if(!un){
+ alert('请选择你的开发者身份');
+ return;
+ }
+ // 团队模式:使用服务器代理,不需要 API 密钥
+ A.demo = true;
+ A.teamMode = true;
+ A.key = '';
+ A.prov = 'custom';
+ A.mdl = TEAM_API.model;
+ lss('zy_teammode','1');
+ setIdentity(un, '');
+
+ // For custom DEV-XXX IDs, try to sync from Notion (non-blocking)
+ if(sel==='__custom__' && DEV_ID_RE.test(un)){
+ syncDevFromNotion(un);
+ }
+
+ showApp();
+}
+
+// Sync developer info from Notion (non-blocking, best-effort)
+function syncDevFromNotion(devId){
+ var apiBase = (location.hostname==='localhost'||location.hostname==='127.0.0.1')
+ ? 'http://localhost:3000' : '';
+ var url = apiBase + '/api/v1/developers/' + encodeURIComponent(devId);
+
+ fetch(url).then(function(r){ return r.json(); }).then(function(data){
+ if(data.found && data.developer){
+ var dev = data.developer;
+ // Update identity with Notion data if available
+ if(dev.name && dev.name !== devId){
+ A.userMeta = {
+ role: 'dev',
+ title: dev.title || dev.role || '开发者',
+ emoji: '💻',
+ badgeCls: 'rb-dev',
+ devId: devId
+ };
+ A.userName = dev.name;
+ lss('zy_uname', A.userName);
+ applyIdentityUI();
+ console.log('[铸渊] Notion 开发者同步成功:', devId, '→', dev.name);
+ }
+ } else {
+ // Developer not found in Notion — try to register (best effort)
+ fetch(apiBase + '/api/v1/developers', {
+ method: 'POST',
+ headers: {'Content-Type':'application/json'},
+ body: JSON.stringify({devId: devId, name: devId})
+ }).then(function(r){ return r.json(); }).then(function(reg){
+ console.log('[铸渊] 开发者自动注册:', reg.created ? '成功' : '已存在', devId);
+ }).catch(function(e){
+ console.log('[铸渊] 开发者注册跳过(后端未就绪):', e.message);
+ });
+ }
+ }).catch(function(e){
+ console.log('[铸渊] Notion 同步跳过(后端未就绪):', e.message);
+ });
+}
+
// ═══════════════════════════════════════════════════════
// SETTINGS PANEL
// ═══════════════════════════════════════════════════════
@@ -1473,7 +1676,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 +1749,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);
+
+ // 从最新消息向前累加,滑动窗口裁剪最早消息
+ // 预算不足时至少保留最近一条用户消息
+ const kept=[];
+ let used=0;
+ for(let i=msgs.length-1;i>=0;i--){
+ const t=estimateTokens(msgs[i].content);
+ if(used+t>budget && kept.length>0) break;
+ kept.unshift(msgs[i]);
+ used+=t;
+ }
+ return [...sysMsgs,...kept];
+}
+
// ═══════════════════════════════════════════════════════
// SEND MESSAGE
// ═══════════════════════════════════════════════════════
@@ -1559,7 +1797,13 @@ async function send(){
setMode(detectMode(txt));
userMsg(txt);
if(A.demo){
- if(GUEST_API.enabled){
+ if(A.teamMode){
+ try{ await teamStreamReply(txt); }
+ catch(e){ console.warn('[团队API] 降级到访客模式:',e.message);
+ try{ await guestStreamReply(txt); }
+ catch(e2){ await demoReply(txt); }
+ }
+ } else if(GUEST_API.enabled){
try{ await guestStreamReply(txt); }
catch(e){ console.warn('[访客API] 降级到演示模式:',e.message); await demoReply(txt); }
} else {
@@ -1584,7 +1828,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',
@@ -1640,6 +1885,69 @@ async function streamReply(txt){
}
}
+// ═══════════════════════════════════════════════════════
+// TEAM API STREAMING(团队模式 · 服务器端代理 · 128k 上下文)
+// 使用服务器端 YUNWU_API_KEY,无需用户提供密钥
+// ═══════════════════════════════════════════════════════
+async function teamStreamReply(txt){
+ A.streaming=true;
+ A.msgs.push({role:'user',content:txt});
+ updSendBtn();
+ const el=addStreamBubble();
+
+ // Resolve proxy URL (relative or absolute)
+ let proxyUrl=TEAM_API.proxyUrl;
+ if(proxyUrl.startsWith('/')){
+ proxyUrl=location.origin+proxyUrl;
+ }
+
+ const reqBody={
+ provider: TEAM_API.provider,
+ model: TEAM_API.model,
+ messages: trimMessagesForContext([{role:'system',content:sysPrompt()}], A.msgs, false),
+ stream: true,
+ temperature: TEAM_API.temperature,
+ max_tokens: TEAM_API.maxTokens,
+ };
+
+ const res=await fetch(proxyUrl,{
+ method:'POST',
+ headers:{'Content-Type':'application/json'},
+ body:JSON.stringify(reqBody),
+ });
+
+ if(!res.ok){
+ let em='[团队API] 返回错误 '+res.status;
+ try{const e=await res.json();em=e.message||em;}catch(_){}
+ throw new Error(em);
+ }
+
+ let full='';
+ const rdr=res.body.getReader();
+ const dec=new TextDecoder();
+ let buf='';
+ while(true){
+ const{done,value}=await rdr.read();
+ if(done) break;
+ buf+=dec.decode(value,{stream:true});
+ const lines=buf.split('\n'); buf=lines.pop();
+ for(const line of lines){
+ if(!line.startsWith('data: ')) continue;
+ const d=line.slice(6);
+ if(d==='[DONE]') continue;
+ try{
+ const p=JSON.parse(d);
+ const delta=p.choices?.[0]?.delta?.content||'';
+ if(delta){full+=delta;el.innerHTML=md(full)+'▋';scrollB();}
+ }catch(_){}
+ }
+ }
+ el.innerHTML=md(full);
+ A.msgs.push({role:'assistant',content:full});
+ addCopyBtns(el);
+ A.streaming=false; updSendBtn(); scrollB();
+}
+
// ═══════════════════════════════════════════════════════
// GUEST API STREAMING (通过 api-proxy 调用 DeepSeek)
// 铸渊人格体系统提示词始终激活,不降级为通用助手
@@ -1667,7 +1975,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,
@@ -1988,6 +2296,10 @@ function setIdentity(userName, ghUser){
A.userName = userName||'';
A.ghUser = ghUser||'';
A.userMeta = userName ? (ROLE_MAP[userName]||null) : null;
+ // Fallback metadata for custom dev IDs (DEV-XXX not in ROLE_MAP)
+ if(!A.userMeta && userName && DEV_ID_RE.test(userName)){
+ A.userMeta = {role:'dev', title:'开发者', emoji:'💻', badgeCls:'rb-dev', devId:userName};
+ }
A.role = A.userMeta?.role || 'guest';
lss('zy_uname', A.userName);
lss('zy_ghuser', A.ghUser);
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();