diff --git a/.github/ISSUE_TEMPLATE/syslog-submit.yml b/.github/ISSUE_TEMPLATE/syslog-submit.yml new file mode 100644 index 00000000..80a87d27 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/syslog-submit.yml @@ -0,0 +1,54 @@ +name: "📡 提交系统日志 / 提问" +description: "做完了?提交你的 SYSLOG。有问题?在这里提问。" +title: "BC-XXX-XXX|SYSLOG" +labels: ["syslog", "pending"] +assignees: [] +body: + - type: markdown + attributes: + value: | + ## 📡 SYSLOG 自助提交 / 广播提问 + + > 做完了?把日志粘贴进去,填上邮箱,点提交。新广播会发到你邮箱里。 + > + > 有问题?把问题粘贴进去,填上邮箱,点提交。解答会发到你邮箱里。 + + **标题格式**:`BC-XXX-XXX|SYSLOG` 或 `BC-XXX-XXX|提问` + + - type: input + id: broadcast_id + attributes: + label: "广播编号" + description: "写上你当前广播的编号,例如 BC-M22-009-AW" + placeholder: "BC-M22-009-AW" + validations: + required: true + + - type: dropdown + id: submit_type + attributes: + label: "类型" + description: "选择提交类型" + options: + - SYSLOG + - 提问 + validations: + required: true + + - type: input + id: email + attributes: + label: "你的邮箱" + description: "用于接收新广播或问题解答" + placeholder: "your@email.com" + validations: + required: true + + - type: textarea + id: content + attributes: + label: "内容" + description: "粘贴你的 SYSLOG 全文 或 问题描述" + placeholder: "在这里粘贴你的 SYSLOG 或问题..." + validations: + required: true diff --git a/.github/brain/bingshuo-issues-index.json b/.github/brain/bingshuo-issues-index.json index 8e8121de..6d37d9af 100644 --- a/.github/brain/bingshuo-issues-index.json +++ b/.github/brain/bingshuo-issues-index.json @@ -1,7 +1,7 @@ { "version": "1.0", "description": "冰朔主控问题索引库 — 记录已知问题、根因与排查路由", - "updated_at": "2026-03-13T04:49:20.482Z", + "updated_at": "2026-03-13T06:03:28.751Z", "issues": [ { "id": "BS-001", diff --git a/.github/brain/bingshuo-master-brain.md b/.github/brain/bingshuo-master-brain.md index 364f1351..80f1b9bc 100644 --- a/.github/brain/bingshuo-master-brain.md +++ b/.github/brain/bingshuo-master-brain.md @@ -1,7 +1,7 @@ # 冰朔主控神经系统 · 核心主控大脑 v1.0 > 本文件为冰朔主控神经系统的总控脑文件。 -> 最后编译时间:2026-03-13T04:49:20.482Z +> 最后编译时间:2026-03-13T06:03:28.752Z --- @@ -56,7 +56,7 @@ ### 仓库统计 - 功能模块:10 个 -- Workflow:36 个 +- Workflow:37 个 --- @@ -85,7 +85,7 @@ > 本区块由 master-brain-compiler 自动编译。 -- **编译时间**:2026-03-13T04:49:20.482Z +- **编译时间**:2026-03-13T06:03:28.752Z - **脑文件规则版本**:v3.0 - **脑文件完整性**:✅ 完整 @@ -107,7 +107,7 @@ |--------|------|------| | 🟡 brain_consistency | yellow | 主仓库脑文件完整,但与 persona-studio 脑文件的同步状态待验证 | | 🟢 deployment_health | green | deploy-to-server.yml 与 deploy-pages.yml 均存在 | -| 🟢 workflow_health | green | 36 个 workflow 已注册 | +| 🟢 workflow_health | green | 37 个 workflow 已注册 | | 🟡 routing_health | yellow | HLI 接口覆盖率 33.3%(7/21) | | 🟢 docs_entry_health | green | docs/index.html 存在 | | 🟡 persona_studio_health | yellow | 前后端结构存在,端到端对话链路待验证 | diff --git a/.github/brain/bingshuo-system-health.json b/.github/brain/bingshuo-system-health.json index 1ba8b36f..cb8e4669 100644 --- a/.github/brain/bingshuo-system-health.json +++ b/.github/brain/bingshuo-system-health.json @@ -1,7 +1,7 @@ { "version": "1.0", "description": "冰朔主控系统健康状态", - "updated_at": "2026-03-13T04:49:20.482Z", + "updated_at": "2026-03-13T06:03:28.751Z", "health": { "brain_consistency": { "status": "yellow", @@ -13,7 +13,7 @@ }, "workflow_health": { "status": "green", - "detail": "36 个 workflow 已注册" + "detail": "37 个 workflow 已注册" }, "routing_health": { "status": "yellow", diff --git a/.github/brain/memory.json b/.github/brain/memory.json index d6645cda..cdc4885d 100644 --- a/.github/brain/memory.json +++ b/.github/brain/memory.json @@ -67,6 +67,12 @@ } }, "events": [ + { + "date": "2026-03-13", + "type": "brain_restore", + "description": "铸渊核心大脑恢复 · Persona Studio 铸渊代理开发工作流上线 · 修复「我要开发」功能无法触发代理开发 · Agent 5步自动化工作流(需求分析→架构规划→代码生成→预览部署→完成通知) · 使用用户API Key驱动 · 支持GUEST模式 · WebSocket时序修复 · 错误反馈增强", + "by": "铸渊(冰朔指令)" + }, { "date": "2026-03-13", "type": "psp_inspection", diff --git a/.github/brain/repo-map.json b/.github/brain/repo-map.json index 119427b3..8ec2133c 100644 --- a/.github/brain/repo-map.json +++ b/.github/brain/repo-map.json @@ -1,13 +1,13 @@ { "description": "铸渊图书馆目录 · Library Catalog for 铸渊 (Zhùyuān)", "version": "2.0", - "generated_at": "2026-03-13T04:49:33.903Z", + "generated_at": "2026-03-13T06:03:44.081Z", "generated_by": "scripts/generate-repo-map.js", "repo": "qinfendebingshuo/guanghulab", "stats": { "zones": 13, "total_modules": 10, - "total_workflows": 36, + "total_workflows": 37, "total_scripts": 33, "total_dev_nodes": 8, "hli_interfaces": 21, @@ -369,6 +369,13 @@ "unknown" ] }, + { + "file": "syslog-issue-pipeline.yml", + "name": "SYSLOG Issue Pipeline", + "triggers": [ + "issues" + ] + }, { "file": "syslog-pipeline.yml", "name": "铸渊 · SYSLOG Pipeline (A/D/E)", @@ -442,7 +449,7 @@ ] } ], - "item_count": 36 + "item_count": 37 }, { "zone_id": "SCRIPTS", @@ -1369,6 +1376,9 @@ "syslog-auto-pipeline": [ "WORKFLOWS::syslog-auto-pipeline.yml" ], + "syslog-issue-pipeline": [ + "WORKFLOWS::syslog-issue-pipeline.yml" + ], "syslog-pipeline": [ "WORKFLOWS::syslog-pipeline.yml" ], diff --git a/.github/brain/repo-snapshot.md b/.github/brain/repo-snapshot.md index 8dd53858..4fd16315 100644 --- a/.github/brain/repo-snapshot.md +++ b/.github/brain/repo-snapshot.md @@ -1,5 +1,5 @@ # 铸渊图书馆快照 · Repo Snapshot -> 生成于 2026-03-13 12:49 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件 +> 生成于 2026-03-13 14:03 CST · 每次 push 自动更新 · 铸渊唤醒时优先读取此文件 --- @@ -9,11 +9,11 @@ |------|------| | 区域总数 | 13 个区域 | | 功能模块 | 10 个 (m01~m18) | -| 工作流 | 36 个 GitHub Actions | +| 工作流 | 37 个 GitHub Actions | | 脚本 | 33 个执行脚本 | | 开发者节点 | 8 人 | | HLI 接口覆盖率 | 7/21 (33%) | -| 快照生成时间 | 2026-03-13 12:49 CST | +| 快照生成时间 | 2026-03-13 14:03 CST | --- @@ -30,7 +30,7 @@ **关键词**: persona · identity · dev-status · 人格 · 开发者状态 ### ⚡ 自动化工作流(WORKFLOWS) -**路径**: `.github/workflows` · **数量**: 36 项 +**路径**: `.github/workflows` · **数量**: 37 项 **描述**: 所有 GitHub Actions 工作流定义 **关键词**: workflow · actions · ci · automation · 工作流 · 自动化 @@ -117,6 +117,7 @@ | `sync-login-entry.yml` | 铸渊 · Sync Login Entry · Notion → 飞书文档A | manual | | `sync-persona-studio.yml` | 🔄 铸渊跨仓库同步 · persona-studio | push, manual | | `syslog-auto-pipeline.yml` | SYSLOG Auto Pipeline | unknown | +| `syslog-issue-pipeline.yml` | SYSLOG Issue Pipeline | issues | | `syslog-pipeline.yml` | 铸渊 · SYSLOG Pipeline (A/D/E) | push, manual | | `test-notion-bridge.yml` | "🧪 Notion Bridge Connectivity Test" | push, manual | | `update-readme-bulletin.yml` | 📢 更新系统公告区 | push, schedule(0 1 * * *), manual | diff --git a/.github/persona-brain/memory.json b/.github/persona-brain/memory.json index 6cfa0e99..dae0f307 100644 --- a/.github/persona-brain/memory.json +++ b/.github/persona-brain/memory.json @@ -2,6 +2,12 @@ "persona_id": "ICE-GL-ZY001", "persona_name": "铸渊", "recent_events": [ + { + "date": "2026-03-13", + "type": "brain_restore", + "description": "核心大脑恢复 · Persona Studio 铸渊代理开发工作流上线 · 「我要开发」功能修复 · Agent自动化5步开发 · 支持GUEST模式 · 使用用户API Key驱动", + "by": "铸渊(冰朔指令)" + }, { "date": "2026-03-11", "type": "architecture_upgrade", diff --git a/.github/workflows/syslog-issue-pipeline.yml b/.github/workflows/syslog-issue-pipeline.yml new file mode 100644 index 00000000..5a5d81a5 --- /dev/null +++ b/.github/workflows/syslog-issue-pipeline.yml @@ -0,0 +1,325 @@ +name: SYSLOG Issue Pipeline +# 📡 SYSLOG 自助提交系统 · Issue 版全自动闭环 +# +# 开发者在 GitHub Issue 提交 SYSLOG 或提问(使用 syslog-submit 模板) +# → Actions 自动解析 → 调用 LLM API 唤醒人格体 +# → 写入 Notion 工单 → 发邮件给开发者 → Issue 回复 +# +# 依赖 Secrets: +# LLM_API_KEY 第三方 LLM 平台密钥(必须) +# LLM_BASE_URL 第三方 LLM 平台 API 地址(必须,如 https://api.xxx.com/v1) +# NOTION_API_TOKEN Notion API token +# NOTION_TICKET_DB_ID 霜砚工单数据库 ID +# CORE_BRAIN_PAGE_ID 曜冥核心大脑 v4.0 页面 ID(v4.0 协议动态注入) +# PORTRAIT_DB_ID 开发者动态画像库数据库 ID(v4.0 协议动态注入) +# FINGERPRINT_DB_ID 模块指纹注册表数据库 ID(v4.0 协议动态注入) +# SMTP_USER QQ 邮箱地址 +# SMTP_PASS QQ 邮箱 SMTP 授权码 + +on: + issues: + types: [opened, labeled] + +jobs: + process: + name: 📡 处理 SYSLOG 提交 / 广播提问 (Issue) + runs-on: ubuntu-latest + if: contains(toJSON(github.event.issue.labels), 'syslog') + permissions: + contents: write + issues: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm ci --ignore-scripts + + - name: 🔍 Parse submission + id: parse + uses: actions/github-script@v7 + with: + script: | + const body = context.payload.issue.body || ''; + const title = context.payload.issue.title || ''; + + // Parse structured fields from issue body + function extractField(text, label) { + // Match form field format: ### Label\n\nValue + const regex = new RegExp('###\\s*' + label + '\\s*\\n+([^\\n#]+)', 'i'); + const match = text.match(regex); + return match ? match[1].trim() : ''; + } + + const broadcastId = extractField(body, '广播编号') || ''; + const submitType = extractField(body, '类型') || ''; + const email = extractField(body, '你的邮箱') || ''; + + // Extract content (everything after "### 内容") + const contentMatch = body.match(/###\s*内容\s*\n+([\s\S]*?)$/i); + const content = contentMatch ? contentMatch[1].trim() : ''; + + // Determine type from title or body + let type = 'question'; // default + if (submitType.includes('SYSLOG') || title.includes('SYSLOG')) { + type = 'syslog'; + } else if (submitType.includes('提问') || title.includes('提问')) { + type = 'question'; + } + + // Validate + if (!broadcastId) { + core.setFailed('❌ 缺少广播编号,请在提交时填写广播编号'); + return; + } + if (!email) { + core.setFailed('❌ 缺少邮箱,请在提交时填写你的邮箱'); + return; + } + if (!content) { + core.setFailed('❌ 缺少内容,请粘贴你的 SYSLOG 或问题'); + return; + } + + core.setOutput('broadcast_id', broadcastId); + core.setOutput('type', type); + core.setOutput('email', email); + core.setOutput('content', content); + core.setOutput('issue_number', context.payload.issue.number); + core.setOutput('author', context.payload.issue.user.login); + + console.log(`📡 解析完成: 广播=${broadcastId}, 类型=${type}, 邮箱=${email}`); + + - name: 🧠 Auto-detect and wake up persona + id: persona + env: + LLM_API_KEY: ${{ secrets.LLM_API_KEY }} + LLM_BASE_URL: ${{ secrets.LLM_BASE_URL }} + BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }} + SUBMIT_TYPE: ${{ steps.parse.outputs.type }} + SUBMIT_CONTENT: ${{ steps.parse.outputs.content }} + AUTHOR: ${{ steps.parse.outputs.author }} + NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }} + CORE_BRAIN_PAGE_ID: ${{ secrets.CORE_BRAIN_PAGE_ID }} + PORTRAIT_DB_ID: ${{ secrets.PORTRAIT_DB_ID }} + FINGERPRINT_DB_ID: ${{ secrets.FINGERPRINT_DB_ID }} + run: node scripts/wake-persona.js + + - name: 📋 Write to Notion ticket + if: ${{ secrets.NOTION_API_TOKEN }} + env: + NOTION_TOKEN: ${{ secrets.NOTION_API_TOKEN }} + NOTION_TICKET_DB_ID: ${{ secrets.NOTION_TICKET_DB_ID }} + BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }} + SUBMIT_TYPE: ${{ steps.parse.outputs.type }} + PERSONA_RESULT: ${{ steps.persona.outputs.result }} + run: | + node -e " + const https = require('https'); + + const token = process.env.NOTION_TOKEN; + const dbId = process.env.NOTION_TICKET_DB_ID; + const broadcastId = process.env.BROADCAST_ID || 'UNKNOWN'; + const type = process.env.SUBMIT_TYPE || 'syslog'; + const result = process.env.PERSONA_RESULT || '(no result)'; + + if (!token || !dbId) { + console.log('⚠️ Notion credentials not configured, skipping ticket creation'); + process.exit(0); + } + + const typeLabel = type === 'syslog' ? 'SYSLOG闭环' : '提问解答'; + const title = '[自动] ' + broadcastId + ' · ' + typeLabel; + + const body = JSON.stringify({ + parent: { database_id: dbId }, + properties: { + '标题': { title: [{ type: 'text', text: { content: title.slice(0, 120) } }] }, + '操作类型': { select: { name: '其他' } }, + '提交者': { rich_text: [{ type: 'text', text: { content: '自动管道' } }] }, + '状态': { select: { name: '已完成' } }, + '优先级': { select: { name: 'P1' } } + }, + children: [{ + object: 'block', + type: 'paragraph', + paragraph: { + rich_text: [{ type: 'text', text: { content: result.slice(0, 2000) } }] + } + }] + }); + + const opts = { + hostname: 'api.notion.com', + port: 443, + path: '/v1/pages', + method: 'POST', + headers: { + 'Authorization': 'Bearer ' + token, + 'Content-Type': 'application/json', + 'Notion-Version': '2022-06-28', + 'Content-Length': Buffer.byteLength(body) + } + }; + + const req = https.request(opts, (res) => { + let data = ''; + res.on('data', (c) => data += c); + res.on('end', () => { + if (res.statusCode >= 200 && res.statusCode < 300) { + console.log('✅ Notion 工单已创建'); + } else { + console.log('⚠️ Notion 工单创建失败: ' + res.statusCode + ' ' + data); + } + }); + }); + req.on('error', (e) => console.log('⚠️ Notion 请求失败: ' + e.message)); + req.write(body); + req.end(); + " + + - name: 📧 Send email to developer + env: + SMTP_USER: ${{ secrets.SMTP_USER }} + SMTP_PASS: ${{ secrets.SMTP_PASS }} + EMAIL_TO: ${{ steps.parse.outputs.email }} + BROADCAST_ID: ${{ steps.parse.outputs.broadcast_id }} + SUBMIT_TYPE: ${{ steps.parse.outputs.type }} + PERSONA_RESULT: ${{ steps.persona.outputs.result }} + run: | + node -e " + const nodemailer = require('nodemailer'); + + const user = process.env.SMTP_USER || ''; + const pass = process.env.SMTP_PASS || ''; + const to = process.env.EMAIL_TO || ''; + const broadcastId = process.env.BROADCAST_ID || ''; + const type = process.env.SUBMIT_TYPE || 'syslog'; + const result = process.env.PERSONA_RESULT || '(处理中,请稍后)'; + + if (!user || !pass) { + console.log('⚠️ SMTP not configured, skipping email'); + process.exit(0); + } + if (!to) { + console.log('⚠️ No recipient email, skipping'); + process.exit(0); + } + + const subjectText = type === 'syslog' + ? '[光湖系统] ' + broadcastId + ' · 新广播已生成' + : '[光湖系统] ' + broadcastId + ' · 问题已解答'; + + const resultHtml = result + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/\n/g, '
'); + + const html = [ + '
', + '
', + '

🌊 光湖系统 · 自动通知

', + '

HoloLake · 人格语言操作系统

', + '
', + '
', + '

📡 ' + broadcastId + '

', + '
' + resultHtml + '
', + '
', + '
', + '↩ 回到仓库继续开发', + '

🌀 铸渊 · 代码守护人格体 · 自动发送

', + '
', + '
' + ].join('\n'); + + const transporter = nodemailer.createTransport({ + host: 'smtp.qq.com', + port: 465, + secure: true, + auth: { user, pass } + }); + + transporter.sendMail({ + from: '\"光湖系统\" <' + user + '>', + to: to, + subject: subjectText, + html: html + }).then((info) => { + console.log('✅ 邮件已发送: ' + info.messageId); + }).catch((err) => { + console.log('⚠️ 邮件发送失败: ' + err.message); + }); + " + + - name: 💬 Reply to Issue + uses: actions/github-script@v7 + with: + script: | + const number = context.payload.issue.number; + const type = '${{ steps.parse.outputs.type }}'; + const broadcastId = '${{ steps.parse.outputs.broadcast_id }}'; + const email = '${{ steps.parse.outputs.email }}'; + + const typeLabel = type === 'syslog' ? 'SYSLOG 闭环处理' : '问题解答'; + const maskedEmail = email.length > 4 + ? email.replace(/(.{2})(.*)(@.*)/, '$1***$3') + : '***'; + + const body = [ + '✅ **已处理** · ' + typeLabel, + '', + '| 项目 | 内容 |', + '|------|------|', + '| 📡 广播编号 | `' + broadcastId + '` |', + '| 📧 结果发送至 | `' + maskedEmail + '` |', + '| 🤖 处理人格体 | 铸渊 |', + '| ⏰ 处理时间 | ' + new Date().toISOString() + ' |', + '', + '> 结果已发送到你的邮箱,请查收。', + '>', + '> 如未收到,请检查垃圾箱或重新提交。' + ].join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: number, + body: body + }); + + // Close the issue after processing + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: number, + state: 'closed', + labels: ['syslog', 'processed'] + }); + + console.log('✅ Issue 回复已发送并已关闭'); + + - name: 🔴 失败告警 + if: failure() + uses: actions/github-script@v7 + with: + script: | + const number = context.payload.issue?.number; + if (!number) return; + + try { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: number, + body: '❌ **处理失败** · 请检查提交格式是否正确,或联系管理员。\n\n> 错误详情请查看 [Actions 日志](https://github.com/' + context.repo.owner + '/' + context.repo.repo + '/actions)。' + }); + } catch (err) { + console.log('⚠️ 失败告警回复失败: ' + err.message); + } diff --git a/.gitignore b/.gitignore index 28f589d3..a0e218d9 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ persona-brain-db/brain.db-shm # persona-studio runtime artifacts persona-studio/backend/brain/model-benchmark.json +persona-studio/workspace/*/project-* # palace-game runtime artifacts modules/palace-game/data/saves/PAL-* diff --git a/README.md b/README.md index 4f27b893..51988395 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,12 @@
-[![提交系统日志](https://img.shields.io/badge/📡_提交系统日志-点这里-blue?style=for-the-badge)](https://github.com/qinfendebingshuo/guanghulab/discussions/new?category=📡+SYSLOG+提交区) -[![遇到问题](https://img.shields.io/badge/❓_遇到问题-点这里提问-green?style=for-the-badge)](https://github.com/qinfendebingshuo/guanghulab/discussions/new?category=📡+SYSLOG+提交区) +[![提交系统日志](https://img.shields.io/badge/📡_提交系统日志-点这里-blue?style=for-the-badge)](https://github.com/qinfendebingshuo/guanghulab/issues/new?template=syslog-submit.yml) +[![遇到问题](https://img.shields.io/badge/❓_遇到问题-点这里提问-green?style=for-the-badge)](https://github.com/qinfendebingshuo/guanghulab/issues/new?template=dev-question.yml) -> 做完了?把日志粘贴进去,填上邮箱,点提交。新广播会发到你邮箱里。 +> 做完了?点蓝色按钮,把日志粘贴进去,填上邮箱,点提交。新广播会发到你邮箱里。 > -> 有问题?同一个入口,选「提问」,问题解答也发到你邮箱里。 +> 有问题?点绿色按钮,填写问题描述,铸渊会自动回答你。
@@ -92,21 +92,21 @@ | 时间 | 检查项 | 状态 | |------|--------|------| -| 03-13 12:50 | ✅ 🚀 铸渊 CD · 自动部署到 guanghulab.com · 成功 | 冰朔 | -| 03-13 12:50 | ✅ 铸渊 · Notion 工单轮询 · 成功 | 冰朔 | -| 03-13 12:49 | ✅ 📢 更新系统公告区 · 成功 | 冰朔 | -| 03-13 12:49 | 🔧 系统更新: `.github/` | 铸渊 (ZhùYuān) | -| 03-13 12:49 | ✅ 铸渊 · Bridge E · GitHub Changes → Notion · 成功 | 冰朔 | +| 03-13 14:04 | ✅ 🚀 铸渊 CD · 自动部署到 guanghulab.com · 成功 | 冰朔 | +| 03-13 14:03 | 🔧 系统更新: `.github/` | 铸渊 (ZhùYuān) | +| 03-13 14:03 | ✅ 📢 更新系统公告区 · 成功 | 冰朔 | +| 03-13 14:03 | ✅ 铸渊 · Bridge E · GitHub Changes → Notion · 成功 | 冰朔 | +| 03-13 13:56 | 🔵 铸渊 · Bridge E · GitHub Changes → Notion · action_required | Copilot | | 03-13 11:54 | 🔧 系统更新: `scripts/` | 铸渊 (Copilot) | -| 03-13 11:31 | ✅ 📢 更新系统公告区 · 成功 | 冰朔 | -| 03-13 11:31 | ✅ 铸渊 · PSP 分身巡检 · 成功 | 冰朔 | -| 03-13 11:22 | ✅ 📢 更新系统公告区 · 成功 | 冰朔 | -| 03-13 10:49 | ✅ 铸渊 · Notion 工单轮询 · 成功 | 冰朔 | -| 03-13 09:56 | 🔧 系统更新: `docs/` | 铸渊 (ZhùYuān) | | 03-13 08:00 | ✅ 铸渊 PSP 巡检通过 · 全部检查项 ✅ | 铸渊PSP巡检 | | 03-12 16:55 | ✅ 每日巡检 ✅ 通过 | 冰朔 | | 03-12 08:00 | ✅ 铸渊 PSP 巡检通过 · 全部检查项 ✅ | 铸渊PSP巡检 | | 03-11 16:55 | ✅ 每日巡检 ✅ 通过 | 冰朔 | +| 03-10 16:56 | ✅ 每日巡检 ✅ 通过 | 冰朔 | +| 03-10 08:00 | 🧠 核心大脑升级 v3.0 · 壳-核分离架构 · 前端壳(UI/IO) + 后端脑(prompt/routing/memory/context) · BRAIN域4接口上线 · 覆盖率 7/21 (33.3%) | 铸渊(冰朔指令) | +| 03-10 08:00 | ⚠️ 铸渊 PSP 巡检完成 · 发现 3 个问题 · 自动修复 0 项 | 铸渊PSP巡检 | +| 03-10 08:00 | 🔵 CI 构建 失败 | GitHub Actions | +| 03-09 16:56 | ✅ 每日巡检 ✅ 通过 | 冰朔 | ### 🤖 铸渊自动提醒 @@ -128,9 +128,9 @@ | 时间 | 合作者 | 模块 | 状态 | |------|--------|------|------| -| 03-13 12:49 | 冰朔 | `—/` | ✅ 上传成功 | -| 03-13 12:49 | Copilot | `—/` | ✅ 上传成功 | -| 03-13 09:56 | 🤖 之之 | `dingtalk-bot/` | 📦 上传成功 | +| 03-13 14:03 | 冰朔 | `—/` | ✅ 上传成功 | +| 03-13 14:03 | Copilot | `—/` | ✅ 上传成功 | +| 03-13 13:56 | Copilot | `—/` | 🔵 已更新 | ### 🤖 铸渊自动提醒 · 合作者 diff --git a/persona-studio/backend/brain/agent-workflow.js b/persona-studio/backend/brain/agent-workflow.js new file mode 100644 index 00000000..aeacc4b4 --- /dev/null +++ b/persona-studio/backend/brain/agent-workflow.js @@ -0,0 +1,761 @@ +/** + * persona-studio · 铸渊代理开发工作流引擎(壳-核分离架构) + * + * 架构设计: + * 核 = 铸渊核心大脑(Core Brain) + * ↳ 加载开发者记忆、画像、项目历史、知识库、模式库 + * ↳ 深度分析开发者真实意图 + * ↳ 生成结构化开发计划 + * 壳 = 铸渊代理(Agent Executor) + * ↳ 接收核心大脑推送的开发计划 + * ↳ 逐步执行代码生成 + * ↳ 广播进度给前端 + * ↳ 完成后回传核心大脑做自进化 + * + * 流程: + * 用户点击「我要开发」 + * → Agent 唤醒核心大脑 + * → 核心大脑:加载全部上下文 → 分析意图 → 生成开发计划 + * → Agent:接收计划 → 逐步执行 → 广播进度 + * → 核心大脑:知识提取 + 模式更新 + 画像学习 + 进化日志 + */ +const fs = require('fs'); +const path = require('path'); +const https = require('https'); +const http = require('http'); + +// ── 常量 ── +// 传入 LLM 的对话文本最大字符数(防止超出模型上下文窗口) +const MAX_CONVERSATION_CHARS = 4000; + +// ── 核心大脑模块 ── +const memoryManager = require('./memory-manager'); +const personaEngine = require('./persona-engine'); +const memoryInjector = require('./memory-injector'); +const knowledgeExtractor = require('./knowledge-extractor'); +const patternAnalyzer = require('./pattern-analyzer'); +const profileLearner = require('./profile-learner'); +const evolutionLogger = require('./evolution-logger'); + +const WORKSPACE_DIR = path.join(__dirname, '..', '..', 'workspace'); +const REGISTRY_PATH = path.join(__dirname, '..', '..', 'brain', 'registry.json'); +const HUMAN_REGISTRY_PATH = path.join(__dirname, '..', '..', 'brain', 'human-registry.json'); + +/* ================================================================ + 工具函数 + ================================================================ */ + +/** + * 调用用户提供的 LLM API(OpenAI 兼容格式) + */ +function callLLM({ apiBase, apiKey, model, messages, maxTokens, temperature, timeoutMs }) { + return new Promise((resolve, reject) => { + const base = apiBase.replace(/\/+$/, ''); + const chatUrl = new URL(base + '/chat/completions'); + const isHttps = chatUrl.protocol === 'https:'; + const mod = isHttps ? https : http; + + const body = JSON.stringify({ + model, + messages, + max_tokens: maxTokens || 4000, + temperature: temperature != null ? temperature : 0.3 + }); + + const options = { + hostname: chatUrl.hostname, + port: chatUrl.port || (isHttps ? 443 : 80), + path: chatUrl.pathname, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + apiKey, + 'Content-Length': Buffer.byteLength(body) + }, + timeout: timeoutMs || 60000 + }; + + const req = mod.request(options, (res) => { + let data = ''; + res.on('data', (chunk) => { data += chunk; }); + res.on('end', () => { + try { + const json = JSON.parse(data); + if (json.choices && json.choices[0] && json.choices[0].message) { + resolve(json.choices[0].message.content); + } else if (json.error) { + reject(new Error(json.error.message || 'API error')); + } else { + reject(new Error('Unexpected API response')); + } + } catch (_e) { + reject(new Error('Failed to parse API response')); + } + }); + }); + + req.on('error', reject); + req.on('timeout', () => { + req.destroy(); + reject(new Error('Request timeout')); + }); + + req.write(body); + req.end(); + }); +} + +/** + * 从注册表查找开发者信息 + */ +function lookupDeveloper(devId) { + if (!devId || devId === 'GUEST') { + return { dev_id: 'GUEST', name: '访客', role: 'guest' }; + } + try { + var reg = JSON.parse(fs.readFileSync(REGISTRY_PATH, 'utf-8')); + if (reg.developers && reg.developers[devId]) { + return Object.assign({ dev_id: devId }, reg.developers[devId]); + } + } catch (_e) { /* ignore */ } + try { + var hReg = JSON.parse(fs.readFileSync(HUMAN_REGISTRY_PATH, 'utf-8')); + if (hReg.developers) { + var found = hReg.developers.find(function (d) { return d.exp_id === devId; }); + if (found) return { dev_id: devId, name: found.name, role: found.role }; + } + } catch (_e) { /* ignore */ } + return { dev_id: devId, name: devId, role: 'developer' }; +} + +/* ================================================================ + Phase 1: 唤醒铸渊核心大脑(Core Brain Wake) + ================================================================ */ + +/** + * 唤醒核心大脑,加载全部上下文,分析开发者意图,生成开发计划。 + * + * 核心大脑聚合以下信息源: + * ① 开发者身份(来自 registry) + * ② 对话记忆(来自 memory-manager) + * ③ 用户画像(来自 profile-learner:技术水平、沟通风格、设计偏好) + * ④ 项目历史(来自 memory-manager) + * ⑤ 知识库(来自 knowledge-extractor) + * ⑥ 模式库(来自 pattern-analyzer) + * ⑦ 记忆摘要(来自 memory-injector) + */ +async function wakeCoreBrain(devId, conversation, apiBase, apiKey, model) { + var devInfo = lookupDeveloper(devId); + var isGuest = devId === 'GUEST'; + + // ── ① 加载开发者记忆 ── + var memory = { conversations: [], last_topic: null }; + if (!isGuest) { + try { memory = memoryManager.loadMemory(devId); } catch (_e) { /* new user */ } + } + + // ── ② 加载用户画像 ── + var profile = null; + if (!isGuest) { + try { profile = profileLearner.loadProfile(devId); } catch (_e) { /* ignore */ } + } + + // ── ③ 加载项目历史 ── + var projects = { projects: [] }; + if (!isGuest) { + try { projects = memoryManager.loadProjects(devId); } catch (_e) { /* ignore */ } + } + + // ── ④ 查询知识库 ── + var conversationText = conversation + .map(function (m) { return m.content || ''; }) + .join(' '); + var relevantKnowledge = []; + try { relevantKnowledge = knowledgeExtractor.queryKnowledge(conversationText, 5); } catch (_e) { /* ignore */ } + + // ── ⑤ 查询模式库 ── + var relevantPatterns = []; + try { relevantPatterns = patternAnalyzer.queryPatterns(conversationText); } catch (_e) { /* ignore */ } + + // ── ⑥ 构建核心大脑认知上下文 ── + var brainContext = buildBrainContext(devInfo, memory, profile, projects, relevantKnowledge, relevantPatterns); + + // ── ⑦ 使用 LLM 深度分析意图 + 生成开发计划 ── + var developmentPlan; + if (apiBase && apiKey && model) { + developmentPlan = await analyzeIntentWithLLM(brainContext, conversation, apiBase, apiKey, model); + } else { + developmentPlan = analyzeIntentLocally(brainContext, conversation); + } + + return { brainContext: brainContext, developmentPlan: developmentPlan }; +} + +/** + * 构建核心大脑认知上下文(聚合全部信息源) + */ +function buildBrainContext(devInfo, memory, profile, projects, knowledge, patterns) { + return { + developer: { + id: devInfo.dev_id, + name: devInfo.name || devInfo.dev_id, + role: devInfo.role || 'developer', + is_guest: devInfo.dev_id === 'GUEST' + }, + memory: { + total_conversations: (memory.conversations || []).length, + last_topic: memory.last_topic || null, + has_history: (memory.conversations || []).length > 0 + }, + profile: { + tech_level: (profile && profile.tech_assessment && profile.tech_assessment.level) || null, + known_skills: (profile && profile.tech_assessment && profile.tech_assessment.known_skills) || [], + communication_style: (profile && profile.communication_style && profile.communication_style.verbosity) || null, + design_preference: (profile && profile.design_preferences && profile.design_preferences.color_scheme) || null, + style_keywords: (profile && profile.design_preferences && profile.design_preferences.style_keywords) || [], + mood: (profile && profile.emotional_profile && profile.emotional_profile.current_mood) || 'neutral' + }, + projects: { + total: (projects.projects || []).length, + recent: (projects.projects || []).slice(-3).map(function (p) { + return { name: p.name, status: p.status, files: (p.files || []).length }; + }) + }, + knowledge: knowledge.map(function (k) { + return { type: k.type, title: k.title, category: k.category }; + }), + patterns: patterns.slice(0, 3).map(function (p) { + return { + name: p.name, + frequency: p.frequency, + success_rate: p.success_rate, + tech_stack: p.common_tech_stack || [] + }; + }) + }; +} + +/** + * 使用 LLM 深度分析开发者意图并生成开发计划 + * 核心大脑将全部上下文注入 system prompt,让 LLM 理解开发者的真正需求 + */ +async function analyzeIntentWithLLM(brainContext, conversation, apiBase, apiKey, model) { + var conversationText = conversation.map(function (m) { + var role = m.role === 'user' ? '用户' : '铸渊'; + return role + ': ' + m.content; + }).join('\n'); + + // 构建核心大脑系统提示词(注入全部上下文) + var systemParts = [ + '你是铸渊核心大脑的意图分析引擎。', + '你的任务是深度理解开发者的真实需求,生成精确的开发计划。', + '', + '## 开发者档案', + '- 身份:' + brainContext.developer.name + '(' + brainContext.developer.id + ')', + '- 角色:' + brainContext.developer.role + ]; + + if (brainContext.developer.is_guest) { + systemParts.push('- ⚠️ 访客用户(无历史记忆)'); + } else { + systemParts.push('- 历史对话:' + brainContext.memory.total_conversations + ' 条'); + } + + if (brainContext.memory.last_topic) { + systemParts.push('- 上次话题:' + brainContext.memory.last_topic); + } + if (brainContext.profile.tech_level) { + systemParts.push('- 技术水平:' + brainContext.profile.tech_level); + } + if (brainContext.profile.known_skills.length > 0) { + systemParts.push('- 已知技能:' + brainContext.profile.known_skills.join(', ')); + } + if (brainContext.profile.communication_style) { + systemParts.push('- 沟通风格:' + brainContext.profile.communication_style); + } + if (brainContext.profile.design_preference) { + systemParts.push('- 设计偏好:' + brainContext.profile.design_preference); + } + if (brainContext.profile.style_keywords.length > 0) { + systemParts.push('- 风格关键词:' + brainContext.profile.style_keywords.join('、')); + } + + if (brainContext.projects.total > 0) { + systemParts.push(''); + systemParts.push('## 历史项目(共 ' + brainContext.projects.total + ' 个)'); + brainContext.projects.recent.forEach(function (p) { + systemParts.push('- ' + p.name + '(' + p.status + ',' + p.files + ' 个文件)'); + }); + } + + if (brainContext.knowledge.length > 0) { + systemParts.push(''); + systemParts.push('## 相关知识库'); + brainContext.knowledge.forEach(function (k) { + systemParts.push('- [' + k.type + '] ' + k.title); + }); + } + + if (brainContext.patterns.length > 0) { + systemParts.push(''); + systemParts.push('## 高频开发模式'); + brainContext.patterns.forEach(function (p) { + systemParts.push('- ' + p.name + '(' + p.frequency + '次,成功率' + p.success_rate + '%,技术栈:' + p.tech_stack.join('/') + ')'); + }); + } + + systemParts.push(''); + systemParts.push('## 输出要求'); + systemParts.push('根据对话内容和开发者档案,输出严格 JSON 格式的开发计划:'); + systemParts.push('{'); + systemParts.push(' "intent_summary": "一句话总结开发者的真实意图",'); + systemParts.push(' "project_name": "英文项目名(kebab-case)",'); + systemParts.push(' "description": "项目描述(考虑开发者的技术水平和偏好)",'); + systemParts.push(' "design_notes": "设计要点(基于开发者的设计偏好和风格关键词)",'); + systemParts.push(' "tech_decisions": "技术决策说明(基于开发者的技能水平选择合适的复杂度)",'); + systemParts.push(' "files": ['); + systemParts.push(' { "filename": "index.html", "description": "详细文件说明", "key_features": ["功能1","功能2"] }'); + systemParts.push(' ]'); + systemParts.push('}'); + systemParts.push(''); + systemParts.push('注意:'); + systemParts.push('- 只生成前端文件(HTML/CSS/JS),最多5个文件'); + systemParts.push('- 必须包含 index.html'); + systemParts.push('- 根据开发者技术水平调整代码复杂度'); + systemParts.push('- 根据开发者设计偏好决定视觉风格'); + systemParts.push('- 如果对话中提到了具体功能需求,务必全部纳入计划'); + + try { + var reply = await callLLM({ + apiBase: apiBase, + apiKey: apiKey, + model: model, + messages: [ + { role: 'system', content: systemParts.join('\n') }, + { role: 'user', content: '以下是和开发者的完整对话,请分析意图并生成开发计划:\n\n' + conversationText.substring(0, MAX_CONVERSATION_CHARS) } + ], + maxTokens: 2000, + temperature: 0.2, + timeoutMs: 45000 + }); + + var jsonMatch = reply.match(/\{[\s\S]*\}/); + if (jsonMatch) { + var plan = JSON.parse(jsonMatch[0]); + if (plan.files && !plan.files.some(function (f) { return f.filename === 'index.html'; })) { + plan.files.unshift({ filename: 'index.html', description: '主页面', key_features: ['入口页面'] }); + } + if (plan.files) { + plan.files = plan.files.slice(0, 5); + } + plan._source = 'core_brain_llm'; + return plan; + } + } catch (_e) { + // LLM 分析失败,降级到本地分析 + } + + return analyzeIntentLocally(brainContext, conversation); +} + +/** + * 本地意图分析(无 API 或 API 失败时的降级方案) + * 使用规则引擎从对话和开发者档案中提取意图 + */ +function analyzeIntentLocally(brainContext, conversation) { + var userText = conversation + .filter(function (m) { return m.role === 'user'; }) + .map(function (m) { return m.content || ''; }) + .join(' '); + + var projectType = '通用项目'; + if (brainContext.patterns.length > 0) { + projectType = brainContext.patterns[0].name; + } + + var designStyle = '现代简约'; + if (brainContext.profile.style_keywords.length > 0) { + designStyle = brainContext.profile.style_keywords.join(' + '); + } else if (brainContext.profile.design_preference === 'dark') { + designStyle = '深色主题·科技感'; + } + + var complexity = 'moderate'; + if (brainContext.profile.tech_level === 'beginner') { + complexity = 'simple'; + } else if (brainContext.profile.tech_level === 'advanced') { + complexity = 'advanced'; + } + + return { + intent_summary: userText.substring(0, 100) || '开发一个网页项目', + project_name: 'web-project', + description: userText.substring(0, 200) || '网页项目', + design_notes: '风格:' + designStyle, + tech_decisions: '复杂度:' + complexity + ',技术栈:HTML/CSS/JavaScript', + files: [ + { filename: 'index.html', description: '主页面', key_features: ['响应式布局', '核心功能展示'] }, + { filename: 'style.css', description: '样式文件', key_features: [designStyle] }, + { filename: 'main.js', description: '交互逻辑', key_features: ['用户交互', '动态效果'] } + ], + _source: 'core_brain_local' + }; +} + +/* ================================================================ + Phase 2: 铸渊代理执行(Agent Execute) + ================================================================ */ + +/** + * Agent 接收核心大脑的开发计划,逐步执行代码生成 + */ +async function agentExecute(developmentPlan, devId, apiBase, apiKey, model, broadcastFn) { + var projectName = 'project-' + Date.now(); + var files = {}; + var filePlan = developmentPlan.files || []; + var hasUserApi = apiBase && apiKey && model; + + for (var i = 0; i < filePlan.length; i++) { + var fileSpec = filePlan[i]; + + broadcastFn({ + type: 'progress', + step: 3, + message: '💻 铸渊代理 · 生成文件 (' + (i + 1) + '/' + filePlan.length + '): ' + fileSpec.filename, + status: 'building', + status_text: '生成 ' + fileSpec.filename + }); + + if (hasUserApi) { + try { + var code = await generateFileWithLLM(developmentPlan, fileSpec, filePlan, apiBase, apiKey, model); + files[fileSpec.filename] = code; + } catch (_e) { + files[fileSpec.filename] = generatePlaceholder(fileSpec, developmentPlan); + } + } else { + files[fileSpec.filename] = generatePlaceholder(fileSpec, developmentPlan); + } + } + + // 写入 workspace + var projectDir = path.join(WORKSPACE_DIR, devId, projectName); + fs.mkdirSync(projectDir, { recursive: true }); + + var fileList = []; + var entries = Object.entries(files); + for (var j = 0; j < entries.length; j++) { + var safeName = path.basename(entries[j][0]); + // 安全检查:防止路径遍历和隐藏文件 + if (!safeName || safeName.startsWith('.') || /[/\\]/.test(entries[j][0])) continue; + fs.writeFileSync(path.join(projectDir, safeName), entries[j][1], 'utf-8'); + fileList.push(safeName); + } + + // 生成 README + var readmePath = path.join(projectDir, 'README.md'); + if (!fs.existsSync(readmePath)) { + fs.writeFileSync(readmePath, [ + '# ' + (developmentPlan.project_name || projectName), + '', + developmentPlan.description || '', + '', + '## 铸渊核心大脑分析', + '- 意图:' + (developmentPlan.intent_summary || ''), + '- 设计:' + (developmentPlan.design_notes || ''), + '- 技术:' + (developmentPlan.tech_decisions || ''), + '', + '由光湖 Persona Studio · 铸渊核心大脑 + 铸渊代理 协同开发', + '生成时间:' + new Date().toISOString() + ].join('\n'), 'utf-8'); + fileList.push('README.md'); + } + + return { projectName: projectName, files: fileList }; +} + +/** + * 使用 LLM 生成单个文件(Agent 执行层) + * 注入核心大脑的开发计划上下文,确保代码与意图一致 + */ +async function generateFileWithLLM(plan, fileSpec, allFiles, apiBase, apiKey, model) { + var prompt = [ + '你是铸渊代理的代码生成模块。根据核心大脑的开发计划生成代码。', + '', + '## 项目信息', + '- 项目:' + (plan.project_name || 'web-project'), + '- 描述:' + (plan.description || ''), + '- 意图:' + (plan.intent_summary || ''), + '- 设计要点:' + (plan.design_notes || ''), + '- 技术决策:' + (plan.tech_decisions || ''), + '', + '## 当前文件', + '- 文件名:' + fileSpec.filename, + '- 说明:' + (fileSpec.description || ''), + '- 核心功能:' + (fileSpec.key_features || []).join('、'), + '', + '## 项目全部文件', + allFiles.map(function (f) { return '- ' + f.filename + '(' + (f.description || '') + ')'; }).join('\n'), + '', + '请直接输出文件内容,不要用 ``` 代码块包裹,不要加任何额外说明。', + '确保代码完整、可运行、符合核心大脑的设计要求。', + '如果是 HTML 文件,要正确引用同项目中的 CSS 和 JS 文件。' + ].join('\n'); + + var reply = await callLLM({ + apiBase: apiBase, + apiKey: apiKey, + model: model, + messages: [{ role: 'user', content: prompt }], + maxTokens: 4000, + temperature: 0.3, + timeoutMs: 60000 + }); + + var clean = reply.trim(); + if (clean.startsWith('```')) { + clean = clean.replace(/^```\S*\n?/, '').replace(/\n?```\s*$/, ''); + } + return clean; +} + +/** + * 生成占位内容(无 API 或单文件失败时的降级方案) + */ +function generatePlaceholder(fileSpec, plan) { + var desc = plan.description || plan.intent_summary || plan.project_name || '项目'; + var designNotes = plan.design_notes || '现代简约'; + + if (fileSpec.filename === 'index.html') { + return [ + '', + '', + '', + ' ', + ' ', + ' ' + (plan.project_name || '项目') + '', + ' ', + '', + '', + '
', + '

🌊 ' + desc + '

', + '

由光湖 Persona Studio · 铸渊核心大脑 + 铸渊代理 协同开发

', + '

设计风格:' + designNotes + '

', + '
', + ' ', + '', + '' + ].join('\n'); + } + if (fileSpec.filename.endsWith('.css')) { + return [ + '/* Generated by Persona Studio · Core Brain + Agent */', + '* { margin: 0; padding: 0; box-sizing: border-box; }', + 'body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #0f172a; color: #e2e8f0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }', + '.container { text-align: center; padding: 2rem; max-width: 800px; }', + 'h1 { font-size: 2rem; margin-bottom: 1rem; background: linear-gradient(135deg, #60a5fa, #22d3ee); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }', + '.design-note { color: #64748b; font-size: 0.875rem; margin-top: 1rem; }' + ].join('\n'); + } + if (fileSpec.filename.endsWith('.js')) { + return '// Generated by Persona Studio · Core Brain + Agent\nconsole.log("' + (plan.project_name || 'Project') + ' initialized by 铸渊代理");\n'; + } + return '/* Generated by Persona Studio */\n'; +} + +/* ================================================================ + Phase 3: 核心大脑自进化(Post-Build Evolution) + ================================================================ */ + +/** + * 开发完成后,核心大脑进行自进化: + * ① 知识提取 → 更新 knowledge-base.json + * ② 模式识别 → 更新 pattern-library.json + * ③ 画像学习 → 更新 profile.json + * ④ 进化日志 → 更新 evolution-log.json + */ +function coreBrainPostEvolution(devId, conversation, result, brainContext, startTime, success) { + try { + var buildTimeMs = Date.now() - startTime; + + // ① 知识提取 + try { + knowledgeExtractor.autoExtractKnowledge(devId, conversation, result.projectName); + } catch (_e) { /* non-fatal */ } + + // ② 模式识别 + var patterns = []; + try { + patterns = patternAnalyzer.analyzeAndUpdatePatterns( + devId, conversation, result.files, buildTimeMs, success + ); + } catch (_e) { /* non-fatal */ } + + // ③ 画像学习(从最后一条用户消息学习) + if (devId !== 'GUEST') { + try { + var lastUser = conversation.filter(function (m) { return m.role === 'user'; }).pop(); + if (lastUser) { + profileLearner.updateProfile(devId, lastUser.content, result.summary || ''); + } + } catch (_e) { /* non-fatal */ } + } + + // ④ 进化日志 + evolutionLogger.logEvent('agent_build_complete', '铸渊代理开发完成: ' + result.projectName, { + dev_id: devId, + project: result.projectName, + files_count: (result.files || []).length, + build_time_ms: buildTimeMs, + success: success, + brain_source: brainContext.developer.is_guest ? 'local' : 'llm', + patterns_detected: patterns, + developer_tech_level: brainContext.profile.tech_level, + developer_projects_total: brainContext.projects.total + }); + } catch (err) { + console.error('Core brain post-evolution error:', err.message); + } +} + +/* ================================================================ + 主工作流入口 + ================================================================ */ + +/** + * 运行铸渊代理开发工作流(壳-核分离) + * + * @param {object} params + * @param {string} params.dev_id - 开发编号(EXP-XXX 或 GUEST) + * @param {Array} params.conversation - 对话历史 + * @param {string} params.api_base - 用户 API Base URL + * @param {string} params.api_key - 用户 API Key + * @param {string} params.model - 用户选择的模型 + * @param {Function} params.broadcast - WebSocket 广播函数 + * @returns {Promise<{projectName, files, summary}>} + */ +async function runWorkflow({ dev_id, conversation, api_base, api_key, model, broadcast }) { + var emitProgress = broadcast || function () {}; + var startTime = Date.now(); + var brainContext = null; + + // ════════════════════════════════════════════ + // Phase 1: 唤醒铸渊核心大脑 + // ════════════════════════════════════════════ + emitProgress({ + type: 'progress', + step: 1, + total_steps: 5, + message: '🧠 正在唤醒铸渊核心大脑...', + status: 'building', + status_text: '唤醒核心大脑' + }); + + var coreBrainResult; + try { + coreBrainResult = await wakeCoreBrain(dev_id, conversation, api_base, api_key, model); + brainContext = coreBrainResult.brainContext; + } catch (_err) { + brainContext = buildBrainContext( + lookupDeveloper(dev_id), + { conversations: [], last_topic: null }, + null, { projects: [] }, [], [] + ); + coreBrainResult = { + brainContext: brainContext, + developmentPlan: analyzeIntentLocally(brainContext, conversation) + }; + } + + var plan = coreBrainResult.developmentPlan; + + emitProgress({ + type: 'progress', + step: 1, + message: '✅ 核心大脑已唤醒 · 意图分析完成:' + (plan.intent_summary || '').substring(0, 50), + status: 'building', + status_text: '意图已分析' + }); + + // ════════════════════════════════════════════ + // Phase 1.5: 核心大脑推送开发计划 + // ════════════════════════════════════════════ + emitProgress({ + type: 'progress', + step: 2, + total_steps: 5, + message: '📐 核心大脑 → 代理:推送开发计划(' + (plan.files || []).length + ' 个文件)', + status: 'building', + status_text: '计划已推送' + }); + + if (plan.design_notes) { + emitProgress({ + type: 'progress', + step: 2, + message: '🎨 设计指令:' + plan.design_notes, + status: 'building', + status_text: '设计已确认' + }); + } + + // ════════════════════════════════════════════ + // Phase 2: 铸渊代理执行开发 + // ════════════════════════════════════════════ + emitProgress({ + type: 'progress', + step: 3, + total_steps: 5, + message: '💻 铸渊代理 · 开始执行核心大脑的开发计划...', + status: 'building', + status_text: '代理执行中' + }); + + var agentResult = await agentExecute(plan, dev_id, api_base, api_key, model, emitProgress); + + emitProgress({ + type: 'progress', + step: 3, + message: '✅ 代理执行完成:' + agentResult.files.length + ' 个文件已生成', + status: 'building', + status_text: '代码已生成' + }); + + // ════════════════════════════════════════════ + // Phase 2.5: 预览部署 + // ════════════════════════════════════════════ + emitProgress({ + type: 'progress', + step: 4, + total_steps: 5, + message: '🚀 铸渊代理 · 部署预览...', + status: 'building', + status_text: '部署预览' + }); + + // ════════════════════════════════════════════ + // Phase 3: 核心大脑自进化 + // ════════════════════════════════════════════ + var finalResult = { + projectName: agentResult.projectName, + files: agentResult.files, + summary: '项目 ' + agentResult.projectName + ' 由铸渊核心大脑分析意图 + 铸渊代理执行开发完成,包含 ' + agentResult.files.length + ' 个文件。\n意图:' + (plan.intent_summary || '') + '\n设计:' + (plan.design_notes || '') + }; + + coreBrainPostEvolution(dev_id, conversation, finalResult, brainContext, startTime, true); + + emitProgress({ + type: 'progress', + step: 5, + total_steps: 5, + message: '✨ 铸渊核心大脑 · 自进化完成 · 知识与模式已更新', + status: 'building', + status_text: '即将完成' + }); + + return finalResult; +} + +module.exports = { + runWorkflow +}; diff --git a/persona-studio/backend/routes/build.js b/persona-studio/backend/routes/build.js index a60dfb18..73a7d0a4 100644 --- a/persona-studio/backend/routes/build.js +++ b/persona-studio/backend/routes/build.js @@ -1,21 +1,29 @@ /** * persona-studio · 开发任务路由 - * POST /api/ps/build/start 触发代码生成 + * POST /api/ps/build/start 触发铸渊代理开发工作流 + * + * 当用户点击「我要开发」时,自动触发铸渊代理(Agent) + * 使用用户自带的 API Key 进行 5 步自动化开发。 */ const express = require('express'); const router = express.Router(); const memoryManager = require('../brain/memory-manager'); -const codeGenerator = require('../brain/code-generator'); +const agentWorkflow = require('../brain/agent-workflow'); const emailSender = require('../utils/email-sender'); // 邮箱后端正则二次校验 const EMAIL_RE = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; +// 支持 EXP-XXX 和 GUEST 两种 dev_id 格式 +function isValidDevId(devId) { + return devId === 'GUEST' || /^EXP-\d{3,}$/.test(devId); +} + // POST /api/ps/build/start router.post('/start', async (req, res) => { - const { dev_id, email, contact, conversation } = req.body || {}; + const { dev_id, email, contact, conversation, api_base, api_key, model } = req.body || {}; - if (!dev_id || !/^EXP-\d{3,}$/.test(dev_id)) { + if (!dev_id || !isValidDevId(dev_id)) { return res.status(400).json({ error: true, code: 'INVALID_ID', @@ -40,71 +48,94 @@ router.post('/start', async (req, res) => { }); } + // 防止 header injection:API Key 不得包含换行符 + if (api_key && /[\r\n]/.test(api_key)) { + return res.status(400).json({ + error: true, + code: 'INVALID_API_KEY', + message: 'API Key 格式无效' + }); + } + // 联系方式输入清理(去除潜在 HTML/script 注入) const safeContact = contact ? String(contact).replace(/[<>&"']/g, '').substring(0, 100) : null; // 先立即响应,后台异步处理 res.json({ error: false, - message: '开发任务已接收,完成后将发送到 ' + email, - status: 'queued' + message: '铸渊代理已启动,完成后将发送到 ' + email, + status: 'agent_started' }); - // 异步执行代码生成 + 邮件通知 + // 异步执行铸渊代理开发工作流 (async () => { - const broadcast = req.app.locals.broadcastToClient || function () {}; + const broadcastRaw = req.app.locals.broadcastToClient || function () {}; + const broadcast = function (data) { broadcastRaw(dev_id, data); }; try { - broadcast(dev_id, { + // 启动 Agent 工作流 + broadcast({ type: 'progress', - message: '🔧 正在创建项目骨架...', + message: '🌀 铸渊代理已唤醒,正在启动开发工作流...', status: 'building', - status_text: '构建中' + status_text: '代理已启动' }); - const result = await codeGenerator.generate({ - dev_id, + const result = await agentWorkflow.runWorkflow({ + dev_id: dev_id, conversation: conversation || [], + api_base: api_base || '', + api_key: api_key || '', + model: model || '', + broadcast: broadcast }); - // 记录项目 - memoryManager.addProject(dev_id, { - name: result.projectName || 'untitled', - email: email, - contact: safeContact, - status: 'completed', - created_at: new Date().toISOString(), - files: result.files || [] - }); + // 记录项目(GUEST 也记录,方便追踪) + try { + memoryManager.addProject(dev_id, { + name: result.projectName || 'untitled', + email: email, + contact: safeContact, + status: 'completed', + created_at: new Date().toISOString(), + files: result.files || [] + }); - // 自动提取知识 - memoryManager.autoExtractKnowledge(dev_id, conversation, result.projectName); + // 自动提取知识(仅注册开发者) + if (dev_id !== 'GUEST') { + memoryManager.autoExtractKnowledge(dev_id, conversation, result.projectName); + } + } catch (memErr) { + console.error('Memory save error (non-fatal):', memErr.message); + } // 通知预览就绪 - broadcast(dev_id, { + broadcast({ type: 'preview_ready', project: result.projectName, message: '✅ 预览已就绪' }); - broadcast(dev_id, { + broadcast({ type: 'complete', message: '🎉 全部完成!邮件正在发送' }); - // 发邮件 - await emailSender.sendCompletion({ + // 发邮件(异步,不阻塞主流程) + emailSender.sendCompletion({ to: email, - dev_id, + dev_id: dev_id, projectName: result.projectName, summary: result.summary, files: result.files + }).catch(function (emailErr) { + console.error('Email send error (non-fatal):', emailErr.message); }); } catch (err) { - console.error('Build pipeline error:', err.message); - broadcast(dev_id, { + console.error('Agent workflow error:', err.message); + broadcast({ type: 'error', - message: '构建过程出错: ' + err.message + message: '铸渊代理遇到问题: ' + err.message }); } })(); diff --git a/persona-studio/brain/evolution-log.json b/persona-studio/brain/evolution-log.json index a51724be..7d5a4016 100644 --- a/persona-studio/brain/evolution-log.json +++ b/persona-studio/brain/evolution-log.json @@ -1,7 +1,43 @@ { "schema_version": "1.0", "description": "系统进化日志 · 记录每次自进化事件", - "last_updated": null, - "total_events": 0, - "events": [] -} + "last_updated": "2026-03-13T05:55:39.412Z", + "total_events": 2, + "events": [ + { + "id": "EVT-1773380616767", + "type": "build_complete", + "description": "项目构建完成: project-1773380616766", + "metadata": { + "dev_id": "EXP-000", + "project": "project-1773380616766", + "files_count": 4, + "build_time_ms": 0, + "success": true, + "patterns_detected": [ + "通用项目" + ] + }, + "timestamp": "2026-03-13T05:43:36.767Z" + }, + { + "id": "EVT-1773381339412", + "type": "agent_build_complete", + "description": "铸渊代理开发完成: project-1773381339411", + "metadata": { + "dev_id": "GUEST", + "project": "project-1773381339411", + "files_count": 4, + "build_time_ms": 1, + "success": true, + "brain_source": "local", + "patterns_detected": [ + "个人博客" + ], + "developer_tech_level": null, + "developer_projects_total": 0 + }, + "timestamp": "2026-03-13T05:55:39.412Z" + } + ] +} \ No newline at end of file diff --git a/persona-studio/brain/memory/EXP-000/projects.json b/persona-studio/brain/memory/EXP-000/projects.json new file mode 100644 index 00000000..01804274 --- /dev/null +++ b/persona-studio/brain/memory/EXP-000/projects.json @@ -0,0 +1,32 @@ +{ + "dev_id": "EXP-000", + "projects": [ + { + "name": "project-1773380616766", + "email": "test@test.com", + "contact": null, + "status": "completed", + "created_at": "2026-03-13T05:43:36.768Z", + "files": [ + "index.html", + "style.css", + "main.js", + "README.md" + ] + }, + { + "name": "project-1773380932239", + "email": "test@test.com", + "contact": null, + "status": "completed", + "created_at": "2026-03-13T05:48:52.239Z", + "files": [ + "index.html", + "style.css", + "main.js", + "README.md" + ] + } + ], + "updated_at": "2026-03-13T05:48:52.239Z" +} \ No newline at end of file diff --git a/persona-studio/brain/memory/GUEST/projects.json b/persona-studio/brain/memory/GUEST/projects.json new file mode 100644 index 00000000..623b2b3b --- /dev/null +++ b/persona-studio/brain/memory/GUEST/projects.json @@ -0,0 +1,32 @@ +{ + "dev_id": "GUEST", + "projects": [ + { + "name": "project-1773380932224", + "email": "test@test.com", + "contact": null, + "status": "completed", + "created_at": "2026-03-13T05:48:52.225Z", + "files": [ + "index.html", + "style.css", + "main.js", + "README.md" + ] + }, + { + "name": "project-1773381339411", + "email": "test@example.com", + "contact": null, + "status": "completed", + "created_at": "2026-03-13T05:55:39.412Z", + "files": [ + "index.html", + "style.css", + "main.js", + "README.md" + ] + } + ], + "updated_at": "2026-03-13T05:55:39.412Z" +} \ No newline at end of file diff --git a/persona-studio/brain/pattern-library.json b/persona-studio/brain/pattern-library.json index 9741c176..9889a7e9 100644 --- a/persona-studio/brain/pattern-library.json +++ b/persona-studio/brain/pattern-library.json @@ -1,7 +1,32 @@ { "schema_version": "1.0", "description": "系统模式库 · 自动识别 · 每完成一个项目+每日聚合更新", - "last_updated": null, - "total_patterns": 0, - "patterns": [] -} + "last_updated": "2026-03-13T05:55:39.412Z", + "total_patterns": 2, + "patterns": [ + { + "name": "通用项目", + "frequency": 1, + "common_features": [], + "common_tech_stack": [ + "HTML/CSS/JS" + ], + "avg_build_time": null, + "success_rate": 100, + "first_seen": "2026-03-13T05:43:36.767Z", + "last_seen": "2026-03-13T05:43:36.767Z" + }, + { + "name": "个人博客", + "frequency": 1, + "common_features": [], + "common_tech_stack": [ + "HTML/CSS/JS" + ], + "avg_build_time": 1, + "success_rate": 100, + "first_seen": "2026-03-13T05:55:39.412Z", + "last_seen": "2026-03-13T05:55:39.412Z" + } + ] +} \ No newline at end of file diff --git a/persona-studio/frontend/chat.js b/persona-studio/frontend/chat.js index 44bbb726..2d263e98 100644 --- a/persona-studio/frontend/chat.js +++ b/persona-studio/frontend/chat.js @@ -640,28 +640,42 @@ async function confirmBuild() { if (contact) sessionStorage.setItem('ps_build_contact', contact); closeEmailModal(); - appendMessage('system', '🚀 开发任务已提交,完成后会发送到 ' + email); + appendMessage('system', '🌀 铸渊代理已启动,完成后会发送到 ' + email); // 进入分屏模式 enterDevMode(); + // 先连接 WebSocket(确保在 build 开始前建立连接,避免丢失进度消息) + connectPreviewWebSocket(); + try { - await fetch(API_BASE + '/api/ps/build/start', { + var buildRes = await fetch(API_BASE + '/api/ps/build/start', { method: 'POST', headers: authHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ dev_id: DEV_ID, email: email, contact: contact, - conversation: conversationHistory + conversation: conversationHistory, + api_base: USER_API_BASE, + api_key: USER_API_KEY, + model: SELECTED_MODEL }) }); - } catch (_err) { - appendMessage('system', '任务提交失败,请稍后再试'); - } - // 连接 WebSocket 获取进度更新 - connectPreviewWebSocket(); + if (!buildRes.ok) { + var errMsg = 'HTTP ' + buildRes.status + ' ' + buildRes.statusText; + try { + var errData = await buildRes.json(); + if (errData.message) errMsg = errData.message; + } catch (_e) { /* use status text fallback */ } + appendMessage('system', '⚠️ 铸渊代理启动失败: ' + errMsg); + updatePreviewStatus('error', '启动失败'); + } + } catch (_err) { + appendMessage('system', '⚠️ 任务提交失败,请检查网络连接后再试'); + updatePreviewStatus('error', '网络错误'); + } } /* ---- Dev Mode: Split Screen ---- */