Merge branch 'main' of https://github.com/qinfendebingshuo/guanghulab
This commit is contained in:
commit
0ab3c09016
|
|
@ -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
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 | 前后端结构存在,端到端对话链路待验证 |
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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(/>/g, '>')
|
||||
.replace(/\n/g, '<br>');
|
||||
|
||||
const html = [
|
||||
'<div style=\"font-family:sans-serif;max-width:700px;margin:0 auto;padding:24px;background:#0f172a;color:#e2e8f0;border-radius:12px\">',
|
||||
'<div style=\"text-align:center;padding:16px 0;border-bottom:1px solid #334155\">',
|
||||
'<h2 style=\"color:#60a5fa;margin:0\">🌊 光湖系统 · 自动通知</h2>',
|
||||
'<p style=\"color:#94a3b8;font-size:14px;margin:8px 0 0\">HoloLake · 人格语言操作系统</p>',
|
||||
'</div>',
|
||||
'<div style=\"padding:20px 0\">',
|
||||
'<p style=\"color:#22d3ee;font-weight:bold\">📡 ' + broadcastId + '</p>',
|
||||
'<div style=\"background:#1e293b;padding:16px;border-radius:8px;margin:12px 0;line-height:1.8\">' + resultHtml + '</div>',
|
||||
'</div>',
|
||||
'<div style=\"border-top:1px solid #334155;padding:16px 0;text-align:center\">',
|
||||
'<a href=\"https://github.com/qinfendebingshuo/guanghulab\" style=\"display:inline-block;padding:8px 20px;background:linear-gradient(135deg,#3b82f6,#22d3ee);color:#fff;text-decoration:none;border-radius:6px;font-weight:600\">↩ 回到仓库继续开发</a>',
|
||||
'<p style=\"color:#64748b;font-size:12px;margin:12px 0 0\">🌀 铸渊 · 代码守护人格体 · 自动发送</p>',
|
||||
'</div>',
|
||||
'</div>'
|
||||
].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);
|
||||
}
|
||||
|
|
@ -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-*
|
||||
|
|
|
|||
34
README.md
34
README.md
|
|
@ -53,12 +53,12 @@
|
|||
|
||||
<div align="center">
|
||||
|
||||
[](https://github.com/qinfendebingshuo/guanghulab/discussions/new?category=📡+SYSLOG+提交区)
|
||||
[](https://github.com/qinfendebingshuo/guanghulab/discussions/new?category=📡+SYSLOG+提交区)
|
||||
[](https://github.com/qinfendebingshuo/guanghulab/issues/new?template=syslog-submit.yml)
|
||||
[](https://github.com/qinfendebingshuo/guanghulab/issues/new?template=dev-question.yml)
|
||||
|
||||
> 做完了?把日志粘贴进去,填上邮箱,点提交。新广播会发到你邮箱里。
|
||||
> 做完了?点蓝色按钮,把日志粘贴进去,填上邮箱,点提交。新广播会发到你邮箱里。
|
||||
>
|
||||
> 有问题?同一个入口,选「提问」,问题解答也发到你邮箱里。
|
||||
> 有问题?点绿色按钮,填写问题描述,铸渊会自动回答你。
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -92,21 +92,21 @@
|
|||
<!-- BINGSHUO_BULLETIN_START -->
|
||||
| 时间 | 检查项 | 状态 |
|
||||
|------|--------|------|
|
||||
| 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 | ✅ 每日巡检 ✅ 通过 | 冰朔 |
|
||||
<!-- BINGSHUO_BULLETIN_END -->
|
||||
|
||||
### 🤖 铸渊自动提醒
|
||||
|
|
@ -128,9 +128,9 @@
|
|||
<!-- COLLABORATOR_BULLETIN_START -->
|
||||
| 时间 | 合作者 | 模块 | 状态 |
|
||||
|------|--------|------|------|
|
||||
| 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 | `—/` | 🔵 已更新 |
|
||||
<!-- COLLABORATOR_BULLETIN_END -->
|
||||
|
||||
### 🤖 铸渊自动提醒 · 合作者
|
||||
|
|
|
|||
|
|
@ -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 [
|
||||
'<!DOCTYPE html>',
|
||||
'<html lang="zh-CN">',
|
||||
'<head>',
|
||||
' <meta charset="UTF-8">',
|
||||
' <meta name="viewport" content="width=device-width, initial-scale=1.0">',
|
||||
' <title>' + (plan.project_name || '项目') + '</title>',
|
||||
' <link rel="stylesheet" href="style.css">',
|
||||
'</head>',
|
||||
'<body>',
|
||||
' <div class="container">',
|
||||
' <h1>🌊 ' + desc + '</h1>',
|
||||
' <p>由光湖 Persona Studio · 铸渊核心大脑 + 铸渊代理 协同开发</p>',
|
||||
' <p class="design-note">设计风格:' + designNotes + '</p>',
|
||||
' </div>',
|
||||
' <script src="main.js"></script>',
|
||||
'</body>',
|
||||
'</html>'
|
||||
].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
|
||||
};
|
||||
|
|
@ -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,34 +48,50 @@ 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
|
||||
});
|
||||
|
||||
// 记录项目
|
||||
// 记录项目(GUEST 也记录,方便追踪)
|
||||
try {
|
||||
memoryManager.addProject(dev_id, {
|
||||
name: result.projectName || 'untitled',
|
||||
email: email,
|
||||
|
|
@ -77,34 +101,41 @@ router.post('/start', async (req, res) => {
|
|||
files: result.files || []
|
||||
});
|
||||
|
||||
// 自动提取知识
|
||||
// 自动提取知识(仅注册开发者)
|
||||
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
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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 ---- */
|
||||
|
|
|
|||
Loading…
Reference in New Issue