feat: 复盘笔记接入梦核飞轮 + 看板右侧栏 UI 重构
- FlywheelStats 聚合跨项目 project_notes(最近 50 条),梦核 prompt 新增【高频陷阱】分析节 - 新增 flywheel-intelligence 蓝图模块,阶段一标记 done - ProjectCard 去重:role/recent_focus/部署链接移至 Dashboard 右侧栏统一展示 - 右侧栏改为卡片式布局,部署环境按钮全宽、带箭头图标 - settings.json 权限模式升级为 bypassPermissions;CLAUDE.md 重构蓝图工作流说明
This commit is contained in:
parent
b6e4fbe3fa
commit
ee4b41f938
@ -6,7 +6,7 @@ description: >
|
||||
成为每个项目的贴身导师。炼境本身亦被纳入其中,
|
||||
形成可自我进化的开发智能闭环。
|
||||
iteration: 1
|
||||
updated: 2026-04-10
|
||||
updated: 2026-04-11
|
||||
|
||||
|
||||
|
||||
@ -265,6 +265,13 @@ modules:
|
||||
progress: 100
|
||||
position: [2500, 0]
|
||||
|
||||
- id: flywheel-intelligence
|
||||
name: 飞轮智能成长
|
||||
area: backend
|
||||
status: in_progress
|
||||
progress: 33
|
||||
position: [1750, 650]
|
||||
|
||||
edges:
|
||||
# 前端依赖
|
||||
- from: workspace-mgmt
|
||||
@ -401,3 +408,11 @@ edges:
|
||||
- from: mcp-server
|
||||
to: project-mentor
|
||||
type: dependency
|
||||
|
||||
# 飞轮智能成长
|
||||
- from: blueprint-feedback
|
||||
to: flywheel-intelligence
|
||||
type: dependency
|
||||
- from: blueprint-flywheel
|
||||
to: flywheel-intelligence
|
||||
type: dependency
|
||||
|
||||
77
.blueprint/modules/flywheel-intelligence.md
Normal file
77
.blueprint/modules/flywheel-intelligence.md
Normal file
@ -0,0 +1,77 @@
|
||||
# 飞轮智能成长
|
||||
|
||||
炼境通过管理项目产生的多维数据反哺自身,形成可自我进化的成长闭环。
|
||||
核心愿景:让炼境像一把可成长神器,执行数据越积越多,自身越来越好用。
|
||||
|
||||
## 背景
|
||||
|
||||
现有飞轮仅覆盖一个维度:usage.json 指标 → 梦核分析 → CONVENTIONS 建议。
|
||||
复盘笔记、任务时长、返工率等执行质量数据已在采集,但没有进入任何反哺路径——数据在"睡觉"。
|
||||
|
||||
本模块分三个阶段逐步打通数据→改善的完整闭环。
|
||||
|
||||
## 阶段触发条件
|
||||
|
||||
- **阶段二启动条件**:阶段一上线后,梦核输出中稳定出现"高频陷阱摘要"板块,且跨项目复盘笔记数量 ≥ 20 条
|
||||
- **阶段三启动条件**:阶段二运行 ≥ 3 个月,accumulated 数据覆盖 ≥ 15 个项目,usage.json 携带 rework_count 和 avg_rounds 字段
|
||||
|
||||
---
|
||||
|
||||
## 任务卡
|
||||
|
||||
### ✅ 阶段一:复盘笔记接入梦核飞轮
|
||||
- status: done
|
||||
- complexity: M
|
||||
- files: src-tauri/src/commands/blueprint_feedback.rs, src/components/blueprint/FlywheelPanel.tsx
|
||||
- acceptance: 梦核 prompt 构建时聚合所有项目的 project_notes;Opus 输出新增"高频陷阱摘要"板块,列出跨项目重复出现的踩坑模式;本地验证:有复盘笔记的项目数据能正确注入 prompt
|
||||
|
||||
阶段一详细设计:
|
||||
- 梦核 prompt 模板增加输入段:通过 MCP 读取各项目 project_notes,按"任务类型 × 是否返工"分组
|
||||
- Opus 输出格式新增板块:
|
||||
```
|
||||
### 高频陷阱(跨项目复盘笔记聚合)
|
||||
- <任务类型>:<踩坑描述>,出现 N 次(项目:A、B、C)
|
||||
```
|
||||
- 修改点:梦核 prompt 构建逻辑(Rust 侧)
|
||||
|
||||
---
|
||||
|
||||
### 阶段二:usage.json 扩展采集维度
|
||||
- status: todo
|
||||
- complexity: M
|
||||
- depends: flywheel-intelligence(阶段一完成后启动)
|
||||
- files: src-tauri/src/commands/blueprint_flywheel.rs
|
||||
- acceptance: usage.json 快照新增 complexity_dist、rework_count、avg_rounds_M 字段;字段值从复盘笔记解析填充;梦核分析可输出"M 级任务实际轮数 vs 预估"对比
|
||||
|
||||
阶段二详细设计:
|
||||
```json
|
||||
"tasks": {
|
||||
...现有字段...,
|
||||
"complexity_dist": { "S": 12, "M": 8, "L": 0 },
|
||||
"rework_count": 3,
|
||||
"avg_rounds_M": 2.4
|
||||
}
|
||||
```
|
||||
- rework_count 和 avg_rounds 从项目 project_notes 中解析"实际轮数"字段聚合
|
||||
|
||||
---
|
||||
|
||||
### 阶段三:执行质量预测层
|
||||
- status: todo
|
||||
- complexity: L
|
||||
- depends: flywheel-intelligence(阶段二完成且数据积累达标后启动)
|
||||
- files: TBD(需 /architect 后确定)
|
||||
- acceptance: TBD
|
||||
|
||||
阶段三方向(待 /architect 设计):
|
||||
- 任务完成时长分布(为 S/M/L 定义时间基准)
|
||||
- 高风险任务预警(特定文件组合 → 历史高返工率)
|
||||
- 跨项目模式库推荐
|
||||
|
||||
> ⚠️ 阶段三为 L 级复杂度,到时须先走 /architect → /splitter 流程,禁止直接写代码。
|
||||
|
||||
## 决策记录
|
||||
|
||||
- 三阶段串行而非并行:数据积累需要时间,阶段二依赖阶段一跑出足够复盘笔记,阶段三依赖阶段二的字段扩展;提前建设无数据支撑的预测层是无效投入
|
||||
- 蓝图管理而非单独文档:三阶段是对炼境自身的迭代开发,bluepint 的 depends 字段天然表达阶段间的触发关系,可视化面板也能直接展示当前在哪个阶段
|
||||
- 不存 CONVENTIONS 全文历史到 DB:Git 已有版本记录,效果对比通过 usage.json 的 conventions_version 分组已足够
|
||||
@ -734,6 +734,175 @@
|
||||
"todo": 0,
|
||||
"total": 140
|
||||
}
|
||||
},
|
||||
{
|
||||
"at": "2026-04-11T02:33:58Z",
|
||||
"blocked_reasons": [],
|
||||
"conventions_version": "1.4.3",
|
||||
"delta": {
|
||||
"newly_blocked": [],
|
||||
"newly_done": [],
|
||||
"unblocked": []
|
||||
},
|
||||
"iteration": 1,
|
||||
"modules": {
|
||||
"blocked": 0,
|
||||
"concept": 0,
|
||||
"done": 34,
|
||||
"in_progress": 0,
|
||||
"planned": 0,
|
||||
"stalled": [],
|
||||
"total": 34
|
||||
},
|
||||
"task_ids": {
|
||||
"blocked": [],
|
||||
"done": [
|
||||
"auto-update/Capabilities 权限配置",
|
||||
"auto-update/下载 & 安装",
|
||||
"auto-update/更新检测",
|
||||
"auto-update/自动检查更新",
|
||||
"auto-update/错误提示",
|
||||
"blueprint-buff/BlueprintView 跨项目切换",
|
||||
"blueprint-buff/Buff 生命周期 Rust 命令",
|
||||
"blueprint-buff/blueprint_buffs 数据表",
|
||||
"blueprint-buff/git watcher + 任务匹配写回 + 飞轮快照",
|
||||
"blueprint-buff/前端 Buff 管理 UI",
|
||||
"blueprint-buff/前端实时刷新",
|
||||
"blueprint-feedback/归档 command",
|
||||
"blueprint-feedback/归档候选展示",
|
||||
"blueprint-feedback/梦核分析入口(蓝图弹窗)",
|
||||
"blueprint-feedback/梦核提示词增加停滞模块数据",
|
||||
"blueprint-flywheel/get_flywheel_stats command",
|
||||
"blueprint-flywheel/get_flywheel_stats 支持迭代感知",
|
||||
"blueprint-flywheel/usage.json 埋点写入",
|
||||
"blueprint-flywheel/梦核提示词生成 command",
|
||||
"blueprint-flywheel/飞轮健康面板",
|
||||
"blueprint-governance/CLAUDE.md 模板定义",
|
||||
"blueprint-governance/CONVENTIONS.md 版本化",
|
||||
"blueprint-governance/GovernancePanel 规则编辑器 UI",
|
||||
"blueprint-governance/get_blueprint_status command",
|
||||
"blueprint-governance/sync/梦核/summary 切换为 effective 内容",
|
||||
"blueprint-governance/sync_blueprint_rules command",
|
||||
"blueprint-governance/批量同步所有项目规则",
|
||||
"blueprint-governance/用户版 CONVENTIONS 存储层初始化",
|
||||
"blueprint-governance/用户版 CONVENTIONS 读写 command",
|
||||
"blueprint-onboarding/generate_blueprint_prompt command",
|
||||
"blueprint-onboarding/蓝图操作弹窗",
|
||||
"blueprint-onboarding/项目列表蓝图状态徽章",
|
||||
"blueprint-reader/合并返回完整蓝图数据",
|
||||
"blueprint-reader/读取 manifest.yaml",
|
||||
"blueprint-reader/读取 modules/*.md",
|
||||
"blueprint-view/.blueprint/ 数据结构设计",
|
||||
"blueprint-view/React Flow 节点图渲染",
|
||||
"blueprint-view/blocked 状态支持",
|
||||
"blueprint-view/下一步汇总面板",
|
||||
"blueprint-view/任务卡复制派发",
|
||||
"blueprint-view/批量执行提示词入口",
|
||||
"blueprint-view/智能连线路由",
|
||||
"blueprint-view/模块详情面板",
|
||||
"blueprint-view/统计汇总条",
|
||||
"blueprint-view/蓝图治理面板",
|
||||
"blueprint-view/蓝图读取 Command",
|
||||
"blueprint-view/边高亮与模块聚焦",
|
||||
"blueprint-view/顶部状态行扩展",
|
||||
"blueprint-view/项目卡片蓝图入口",
|
||||
"cicd-workflow/Actions 运行历史",
|
||||
"cicd-workflow/CI/CD 配置 CRUD",
|
||||
"cicd-workflow/Tauri OSS 分发模板",
|
||||
"cicd-workflow/Web SSH 部署模板",
|
||||
"cicd-workflow/Workflow 文件生成",
|
||||
"devtools-scan/WSL 工具扫描",
|
||||
"devtools-scan/Windows 工具扫描",
|
||||
"devtools-scan/工具信息持久化",
|
||||
"git-ops/上游状态检测",
|
||||
"git-ops/分支管理",
|
||||
"git-ops/基础操作",
|
||||
"github-auth/OAuth Device Flow",
|
||||
"github-auth/Token 管理",
|
||||
"github-publish/.gitignore 生成",
|
||||
"github-publish/Git 初始化 & 首次推送",
|
||||
"github-publish/创建 GitHub 仓库",
|
||||
"github-publish/扫描本地 Git 状态",
|
||||
"health-center/T1 · Backend 健康检查聚合命令",
|
||||
"health-center/T2 · 质量指标聚合",
|
||||
"health-center/T3 · 前端健康中心页面",
|
||||
"health-center/T4 · 扩展 MCP get_diagnostics",
|
||||
"mcp-config-inject/加入产品组时注入配置",
|
||||
"mcp-config-inject/端口变更时重新注入所有配置",
|
||||
"mcp-config-inject/退出产品组时清除配置",
|
||||
"mcp-server/MCP 端口可配置(Rust 侧)",
|
||||
"mcp-server/启动时绑定 HTTP 端口",
|
||||
"mcp-server/实现 MCP JSON-RPC 基础协议",
|
||||
"mcp-server/实现产品组上下文工具",
|
||||
"product-group-mcp/产品组详情显示 MCP 注入状态",
|
||||
"product-group-mcp/设置页添加 MCP 端口配置",
|
||||
"project-dashboard/分组画布",
|
||||
"project-dashboard/项目卡片列表",
|
||||
"project-dashboard/项目发现面板",
|
||||
"project-dashboard/项目快捷操作",
|
||||
"project-env-scan/环境信息持久化",
|
||||
"project-env-scan/项目环境检测",
|
||||
"project-mentor/T1 · 后端聚合 command(MentorContext)",
|
||||
"project-mentor/T10 · 启动健康扫描 + 前端 Alert Banner",
|
||||
"project-mentor/T11 · 项目历史快照",
|
||||
"project-mentor/T2 · MCP 项目导师查询接口",
|
||||
"project-mentor/T3 · 前端导师面板",
|
||||
"project-mentor/T4 · 炼境自指接入",
|
||||
"project-mentor/T5 · project_notes 数据层 + 后端命令",
|
||||
"project-mentor/T6 · MCP append_project_note 工具",
|
||||
"project-mentor/T7 · MentorPanel 展示 AI 笔记",
|
||||
"project-mentor/T8 · 后端全组巡检命令",
|
||||
"project-mentor/T9 · 前端全组巡检按钮",
|
||||
"project-mgmt/子文件夹扫描",
|
||||
"project-mgmt/批量导入项目",
|
||||
"project-mgmt/项目 CRUD",
|
||||
"project-mgmt/项目档案(Profile)",
|
||||
"project-templates/从模板创建项目",
|
||||
"project-templates/内置模板种植",
|
||||
"project-templates/模板 CRUD",
|
||||
"project-tools/工具 CRUD",
|
||||
"project-tools/工具启动",
|
||||
"repo-registry/仓库导入",
|
||||
"repo-registry/仓库挂载",
|
||||
"repo-registry/仓库注册表管理",
|
||||
"runtime-diagnostics/T1 · SQLite runtime_logs 表",
|
||||
"runtime-diagnostics/T2 · 替换 eprintln! 为结构化日志",
|
||||
"runtime-diagnostics/T3 · MCP Server 新增 get_diagnostics 工具",
|
||||
"runtime-diagnostics/T4 · 注入失败结果返回前端",
|
||||
"runtime-diagnostics/T5 · 设置页 MCP 真实健康检查",
|
||||
"settings-page/WSL 发行版选择",
|
||||
"settings-page/关于 & 更新",
|
||||
"settings-page/终端配置",
|
||||
"settings-page/编辑器检测",
|
||||
"shell-launch/打开终端",
|
||||
"shell-launch/打开编辑器",
|
||||
"sqlite-db/数据库迁移",
|
||||
"sqlite-db/连接池初始化",
|
||||
"tags-groups/分组管理",
|
||||
"tags-groups/标签管理",
|
||||
"tray-service/关闭窗口最小化到托盘",
|
||||
"tray-service/系统托盘图标与菜单",
|
||||
"tray-service/集成 tauri-plugin-single-instance",
|
||||
"v2rayn-import/当前节点读取",
|
||||
"v2rayn-import/数据库路径检测",
|
||||
"v2rayn-import/节点列表扫描",
|
||||
"workspace-mgmt/空间 CRUD",
|
||||
"workspace-mgmt/空间级设置",
|
||||
"workspace-mgmt/部署命令管理",
|
||||
"wsl-proxy/代理一致性测试",
|
||||
"wsl-proxy/代理同步",
|
||||
"wsl-proxy/代理清除",
|
||||
"wsl-proxy/代理状态检测"
|
||||
]
|
||||
},
|
||||
"tasks": {
|
||||
"blocked": 0,
|
||||
"dispatched": 0,
|
||||
"done": 136,
|
||||
"in_progress": 0,
|
||||
"todo": 0,
|
||||
"total": 140
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -13,6 +13,6 @@
|
||||
]
|
||||
},
|
||||
"permissions": {
|
||||
"defaultMode": "acceptEdits"
|
||||
"defaultMode": "bypassPermissions"
|
||||
}
|
||||
}
|
||||
48
CLAUDE.md
48
CLAUDE.md
@ -22,6 +22,12 @@ src-tauri/src/commands/ Tauri command 实现
|
||||
docs/ 部署和更新指南
|
||||
```
|
||||
|
||||
## 命令执行规则
|
||||
|
||||
- 所有命令直接用 Bash tool 执行,禁止输出命令让用户手动运行
|
||||
- `pnpm tauri build` / `cargo build --release` 等 Rust 构建用 `run_in_background: true` + `timeout: 600000`(首次编译可能需要 10 分钟)
|
||||
- 超过 10 分钟的任务(如完整 release build)改为输出单行完整命令,让用户 `! <命令>` 一键执行
|
||||
|
||||
## 技能使用规则
|
||||
|
||||
根据任务卡 complexity 决定执行后的检查:
|
||||
@ -36,27 +42,39 @@ docs/ 部署和更新指南
|
||||
- 代码重构/简化:/simplify → /code-review
|
||||
- 发现深层问题:/Dev-deep-think
|
||||
|
||||
<!-- BLUEPRINT_MANAGED_START version="1.4.2" -->
|
||||
<!-- BLUEPRINT_MANAGED_START version="1.4.3" -->
|
||||
## 项目蓝图
|
||||
|
||||
本项目使用 `.blueprint/` 目录维护项目全景架构图,驱动需求讨论和任务管理。
|
||||
|
||||
**每次对话都应遵循以下流程:**
|
||||
### 对话开始时必须执行
|
||||
|
||||
### 1. 了解当前状态
|
||||
对话开始时,先读取 `.blueprint/manifest.yaml` 了解项目模块和状态。
|
||||
1. 读取 `.blueprint/manifest.yaml` 了解项目全景和当前状态
|
||||
2. 读取 `.blueprint/CONVENTIONS.md` 了解完整工作流规则
|
||||
|
||||
### 2. 讨论需求时更新蓝图
|
||||
- 确认了新需求 → 在 manifest.yaml 新增模块,创建 `.blueprint/modules/<id>.md`
|
||||
- 拆分了大需求 → 在模块文件中添加任务卡
|
||||
- 调整了方向 → 更新模块关系(edges)
|
||||
### 需求讨论 → 蓝图同步规则
|
||||
|
||||
### 3. 完成实现后标记蓝图
|
||||
- 完成了功能 → 更新对应任务卡状态为 `done`(前缀改为 ✅)
|
||||
- 更新 manifest.yaml 顶部的 `updated` 日期
|
||||
| 用户说的 | Claude 应做的 |
|
||||
|----------|--------------|
|
||||
| "我想加个 XX 功能" | 确认需求后:manifest 新增模块(status: concept),创建 `.blueprint/modules/<id>.md` |
|
||||
| "XX 功能需要 A、B、C" | 在模块文件中拆分为任务卡 |
|
||||
| "这个方案确定了" | 模块 status → planned,补充任务卡 files/acceptance |
|
||||
| "开始做 XX" | 模块 status → in_progress |
|
||||
| 没提蓝图但在讨论功能 | 主动提议更新蓝图 |
|
||||
|
||||
### 4. 任务卡规范
|
||||
详见 `.blueprint/CONVENTIONS.md`,核心规则:
|
||||
- 任务卡同时具备 `files` + `acceptance` + complexity `S/M` → 标记为 📋 可派发
|
||||
- 可派发的任务卡可以直接交给 Claude Agent 独立完成
|
||||
### 复杂度决策(讨论新功能 / 拆解需求时)
|
||||
|
||||
| complexity | 执行流程 |
|
||||
|-----------|---------|
|
||||
| S / M | 直接拆任务卡,确保每张卡有 `files` + `acceptance` + `complexity` → 标记 📋 |
|
||||
| L(复杂系统设计) | 先 `/architect` 输出设计文档,用户确认后 `/splitter` 拆成 S/M 任务卡 |
|
||||
|
||||
> L 级任务禁止直接写代码,必须先经过 `/architect` → `/splitter` 流程。
|
||||
|
||||
### 任务执行两阶段提交
|
||||
|
||||
- **开始写代码前**:任务卡前缀改为 🔵,status → in_progress
|
||||
- **完成验收后**:任务卡前缀改为 ✅,status → done,更新 manifest `updated` 日期
|
||||
|
||||
完整规则(迭代管理、阻塞处理、复盘笔记等)详见 `.blueprint/CONVENTIONS.md`。
|
||||
<!-- BLUEPRINT_MANAGED_END -->
|
||||
|
||||
@ -1364,6 +1364,14 @@ pub struct IterationJump {
|
||||
pub rate_after: f64,
|
||||
}
|
||||
|
||||
/// 单条跨项目复盘笔记(Claude 通过 MCP 写入)
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ProjectNoteEntry {
|
||||
pub project_name: String,
|
||||
pub content: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct FlywheelStats {
|
||||
pub cohorts: Vec<FlywheelCohort>,
|
||||
@ -1378,6 +1386,8 @@ pub struct FlywheelStats {
|
||||
pub stalled_modules: Vec<String>,
|
||||
pub total_projects_scanned: u32,
|
||||
pub projects_with_data: u32,
|
||||
/// 跨项目复盘笔记(最近 50 条,按时间倒序)
|
||||
pub project_notes: Vec<ProjectNoteEntry>,
|
||||
}
|
||||
|
||||
/// 内部:单项目最新快照的指标摘要
|
||||
@ -1577,6 +1587,8 @@ pub fn get_flywheel_stats(project_paths: Vec<String>) -> Result<FlywheelStats, S
|
||||
.map(|(reason, count)| BlockedReasonCount { reason, count })
|
||||
.collect();
|
||||
|
||||
let project_notes = collect_flywheel_notes(&project_paths);
|
||||
|
||||
Ok(FlywheelStats {
|
||||
cohorts,
|
||||
top_blocked_reasons,
|
||||
@ -1586,9 +1598,62 @@ pub fn get_flywheel_stats(project_paths: Vec<String>) -> Result<FlywheelStats, S
|
||||
stalled_modules,
|
||||
total_projects_scanned: total_scanned,
|
||||
projects_with_data,
|
||||
project_notes,
|
||||
})
|
||||
}
|
||||
|
||||
/// 从 SQLite 收集各项目的 Claude 复盘笔记(按 win_path 匹配项目,取最近 50 条)。
|
||||
/// DB 访问失败时静默返回空列表,不影响主流程。
|
||||
fn collect_flywheel_notes(project_paths: &[String]) -> Vec<ProjectNoteEntry> {
|
||||
let conn = match crate::db::pool().get() {
|
||||
Ok(c) => c,
|
||||
Err(_) => return vec![],
|
||||
};
|
||||
|
||||
let mut notes: Vec<ProjectNoteEntry> = Vec::new();
|
||||
|
||||
for path_str in project_paths {
|
||||
// 通过 win_path 或 wsl_path 查找 project_id 和 name
|
||||
let proj: Result<(String, String), _> = conn.query_row(
|
||||
"SELECT id, name FROM projects WHERE win_path = ?1 OR wsl_path = ?1 LIMIT 1",
|
||||
rusqlite::params![path_str],
|
||||
|row| Ok((row.get(0)?, row.get(1)?)),
|
||||
);
|
||||
let (project_id, project_name) = match proj {
|
||||
Ok(v) => v,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let mut stmt = match conn.prepare(
|
||||
"SELECT content, created_at FROM project_notes
|
||||
WHERE project_id = ?1
|
||||
ORDER BY id DESC LIMIT 20",
|
||||
) {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let rows = stmt.query_map(
|
||||
rusqlite::params![project_id],
|
||||
|row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)),
|
||||
);
|
||||
if let Ok(iter) = rows {
|
||||
for row in iter.filter_map(|r| r.ok()) {
|
||||
notes.push(ProjectNoteEntry {
|
||||
project_name: project_name.clone(),
|
||||
content: row.0,
|
||||
created_at: row.1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按时间倒序,限 50 条(避免 prompt 过长)
|
||||
notes.sort_by(|a, b| b.created_at.cmp(&a.created_at));
|
||||
notes.truncate(50);
|
||||
notes
|
||||
}
|
||||
|
||||
// ── 梦核提示词生成 ────────────────────────────────────────────────────────────
|
||||
|
||||
/// 从完整 CONVENTIONS 中抽取对梦核有判断价值的规则段落。
|
||||
@ -1711,6 +1776,31 @@ pub fn generate_muhe_prompt(stats: FlywheelStats) -> String {
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
// ── 复盘笔记 ──────────────────────────────────────────────────────────────
|
||||
let notes_summary = if stats.project_notes.is_empty() {
|
||||
"(暂无复盘笔记——Claude 尚未在执行 M/L 任务后写入笔记)".to_string()
|
||||
} else {
|
||||
// 按项目分组展示
|
||||
let mut by_project: std::collections::BTreeMap<String, Vec<&ProjectNoteEntry>> = Default::default();
|
||||
for note in &stats.project_notes {
|
||||
by_project.entry(note.project_name.clone()).or_default().push(note);
|
||||
}
|
||||
let mut sections: Vec<String> = Vec::new();
|
||||
for (proj, entries) in &by_project {
|
||||
sections.push(format!("#### {}", proj));
|
||||
for e in entries {
|
||||
// 多行内容缩进,保持 prompt 可读性
|
||||
let indented = e.content.lines()
|
||||
.map(|l| format!(" {}", l))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
sections.push(format!("- `{}`\n{}", e.created_at, indented));
|
||||
}
|
||||
}
|
||||
sections.join("\n")
|
||||
};
|
||||
let notes_total = stats.project_notes.len();
|
||||
|
||||
format!(r#"你是炼境(Dev Manager)的蓝图架构师,负责对飞轮运转数据进行记忆巩固分析。
|
||||
|
||||
## 飞轮运转数据(来自炼境跨项目聚合)
|
||||
@ -1737,6 +1827,13 @@ pub fn generate_muhe_prompt(stats: FlywheelStats) -> String {
|
||||
### 停滞模块(in_progress 但无可推进任务,格式:项目名/模块id)
|
||||
{stalled_modules_summary}
|
||||
|
||||
### 复盘笔记(跨项目 Claude 执行记录,共 {notes_total} 条)
|
||||
|
||||
> 笔记由 Claude 在完成 M/L 任务后通过 MCP 写入,结构化格式为【复盘】开头。
|
||||
> 请重点识别:① 多次出现的相同踩坑;② 返工率高的任务类型;③ 有效策略可固化为规范。
|
||||
|
||||
{notes_summary}
|
||||
|
||||
---
|
||||
|
||||
## 当前 CONVENTIONS.md(v{conventions_version})规则摘要
|
||||
@ -1749,12 +1846,30 @@ pub fn generate_muhe_prompt(stats: FlywheelStats) -> String {
|
||||
|
||||
## 你的任务:记忆巩固
|
||||
|
||||
请完成以下两件事:
|
||||
请完成以下三件事:
|
||||
|
||||
### 【高频陷阱】复盘笔记中的执行模式分析
|
||||
|
||||
仅当复盘笔记数量 > 0 时执行,否则跳过本节。
|
||||
|
||||
分析维度:
|
||||
1. 哪类任务(任务类型 × 复杂度)返工率最高?
|
||||
2. 相同踩坑在多个项目重复出现了吗?根因是什么?
|
||||
3. 有哪些有效策略已经在多个任务中奏效,可以固化为规范?
|
||||
4. 有哪些遗留风险被多次提及,说明系统存在尚未解决的脆弱点?
|
||||
|
||||
输出格式:
|
||||
```
|
||||
### 高频陷阱摘要(来自复盘笔记)
|
||||
- **[任务类型]** <踩坑描述>,出现 N 次(涉及项目:A、B)
|
||||
→ 建议:<一句话规避方式>
|
||||
```
|
||||
若笔记数不足以识别模式(< 5 条),输出"笔记积累不足,暂无高频模式"。
|
||||
|
||||
### 【固化】哪些模式值得写进 CONVENTIONS?
|
||||
|
||||
判断标准:
|
||||
1. 某类阻塞在多个项目重复出现 → 在 CONVENTIONS 增加预防性规范
|
||||
1. 高频陷阱分析中出现 2 次以上的踩坑 → 在 CONVENTIONS 增加预防性规范
|
||||
2. 有队列数据显示某版本后可派发率/任务完成率明显提升 → 提炼有效实践
|
||||
3. 当前 CONVENTIONS 未覆盖但数据反映的真实问题
|
||||
|
||||
@ -1785,6 +1900,8 @@ pub fn generate_muhe_prompt(stats: FlywheelStats) -> String {
|
||||
ai_stale_summary = ai_stale_summary,
|
||||
iteration_summary = iteration_summary,
|
||||
stalled_modules_summary = stalled_modules_summary,
|
||||
notes_total = notes_total,
|
||||
notes_summary = notes_summary,
|
||||
conventions_version = effective_conventions_version(),
|
||||
conventions = conventions_rules_summary(),
|
||||
)
|
||||
|
||||
@ -348,13 +348,13 @@ function ProjectRow({
|
||||
<ProjectCard project={p} role={role} spacesJson={spacesJson} />
|
||||
</div>
|
||||
|
||||
{/* 右:部署信息(与卡片同行对齐) */}
|
||||
<div className="w-72 shrink-0 p-4 flex flex-col gap-2">
|
||||
{/* 状态 + 角色 */}
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{/* 右:部署信息 */}
|
||||
<div className="w-72 shrink-0 p-4 flex flex-col gap-2.5">
|
||||
{/* 状态 + 角色 + 时间 */}
|
||||
<div className="flex items-center gap-1.5 flex-wrap">
|
||||
{p.status && <StatusBadge status={p.status} />}
|
||||
{role && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 rounded bg-purple-50 text-purple-600 border border-purple-100">
|
||||
<span className="text-[10px] px-1.5 py-0.5 rounded-full bg-purple-50 text-purple-600 border border-purple-100 font-medium">
|
||||
{role}
|
||||
</span>
|
||||
)}
|
||||
@ -363,38 +363,52 @@ function ProjectRow({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* recent_focus */}
|
||||
{/* 当前专注 */}
|
||||
{p.recent_focus && (
|
||||
<p className="text-[11px] text-indigo-500 leading-relaxed line-clamp-2">
|
||||
<div className="bg-indigo-50 border border-indigo-100 rounded-md px-2.5 py-2">
|
||||
<p className="text-[11px] text-indigo-600 leading-relaxed line-clamp-3">
|
||||
📌 {p.recent_focus}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* URL */}
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{/* 部署环境入口 */}
|
||||
{(p.prod_url || p.staging_url) && (
|
||||
<div className="flex flex-col gap-1.5">
|
||||
{p.prod_url && (
|
||||
<button
|
||||
onClick={() => openUrl(p.prod_url!).catch(() => {})}
|
||||
className="flex items-center gap-1 text-[11px] px-2 py-0.5 rounded bg-emerald-50 text-emerald-700 border border-emerald-200 hover:bg-emerald-100 transition-colors"
|
||||
className="flex items-center gap-2 text-[11px] px-2.5 py-2 rounded-md bg-emerald-50 text-emerald-700 border border-emerald-200 hover:bg-emerald-100 transition-colors w-full text-left"
|
||||
title={p.prod_url}
|
||||
>
|
||||
🌐 生产
|
||||
<span>🌐</span>
|
||||
<span className="font-medium">生产环境</span>
|
||||
<svg className="w-3 h-3 ml-auto text-emerald-400 shrink-0" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M6.22 8.72a.75.75 0 001.06 1.06l5.22-5.22v1.69a.75.75 0 001.5 0V3a.75.75 0 00-.75-.75H9.5a.75.75 0 000 1.5h1.69L6.22 8.72z"/><path d="M3.5 6.75a.75.75 0 00-.75.75v5.75c0 .414.336.75.75.75h5.75a.75.75 0 000-1.5H4.25V7.5a.75.75 0 00-.75-.75z"/>
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
{p.staging_url && (
|
||||
<button
|
||||
onClick={() => openUrl(p.staging_url!).catch(() => {})}
|
||||
className="flex items-center gap-1 text-[11px] px-2 py-0.5 rounded bg-amber-50 text-amber-700 border border-amber-200 hover:bg-amber-100 transition-colors"
|
||||
className="flex items-center gap-2 text-[11px] px-2.5 py-2 rounded-md bg-amber-50 text-amber-700 border border-amber-200 hover:bg-amber-100 transition-colors w-full text-left"
|
||||
title={p.staging_url}
|
||||
>
|
||||
🧪 测试
|
||||
<span>🧪</span>
|
||||
<span className="font-medium">测试环境</span>
|
||||
<svg className="w-3 h-3 ml-auto text-amber-400 shrink-0" viewBox="0 0 16 16" fill="currentColor">
|
||||
<path d="M6.22 8.72a.75.75 0 001.06 1.06l5.22-5.22v1.69a.75.75 0 001.5 0V3a.75.75 0 00-.75-.75H9.5a.75.75 0 000 1.5h1.69L6.22 8.72z"/><path d="M3.5 6.75a.75.75 0 00-.75.75v5.75c0 .414.336.75.75.75h5.75a.75.75 0 000-1.5H4.25V7.5a.75.75 0 00-.75-.75z"/>
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 服务器备注 */}
|
||||
{p.server_note && (
|
||||
<p className="text-[11px] text-gray-400" title={p.server_note}>🖥 {p.server_note}</p>
|
||||
<div className="bg-gray-50 border border-gray-100 rounded-md px-2.5 py-2">
|
||||
<p className="text-[11px] text-gray-500 leading-relaxed">🖥 {p.server_note}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 无信息提示 */}
|
||||
@ -402,13 +416,13 @@ function ProjectRow({
|
||||
<p className="text-[11px] text-gray-300 italic">未配置部署信息</p>
|
||||
)}
|
||||
|
||||
{/* 部署按钮 */}
|
||||
{/* 部署配置按钮 */}
|
||||
<div className="mt-auto pt-1">
|
||||
<button
|
||||
onClick={() => onDeploy(p)}
|
||||
className="px-2.5 py-1 rounded text-[11px] border border-gray-200 text-gray-500 hover:bg-gray-50 transition-colors"
|
||||
className="w-full px-2.5 py-1.5 rounded-md text-[11px] border border-gray-200 text-gray-500 hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
🚀 部署
|
||||
🚀 部署配置
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -354,11 +354,6 @@ export function ProjectCard({ project: p, role, spacesJson }: Props) {
|
||||
{p.type}
|
||||
</span>
|
||||
)}
|
||||
{role && (
|
||||
<span className="px-1.5 py-0.5 rounded text-xs bg-purple-50 text-purple-600 border border-purple-100">
|
||||
{role}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{p.description && (
|
||||
<p className="text-xs text-gray-400 mt-1 leading-relaxed line-clamp-2">{p.description}</p>
|
||||
@ -407,13 +402,6 @@ export function ProjectCard({ project: p, role, spacesJson }: Props) {
|
||||
|
||||
{/* ── 元信息区 ── */}
|
||||
<div className="px-5 flex flex-col gap-2.5 pb-3">
|
||||
{/* Recent focus */}
|
||||
{p.recent_focus && (
|
||||
<p className="text-xs text-indigo-500 bg-indigo-50 rounded-md px-2.5 py-1.5 leading-relaxed">
|
||||
📌 {p.recent_focus}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Tech stack tags */}
|
||||
{tags.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1">
|
||||
@ -454,34 +442,6 @@ export function ProjectCard({ project: p, role, spacesJson }: Props) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 部署链接 */}
|
||||
{(p.prod_url || p.staging_url || p.server_note) && (
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
{p.prod_url && (
|
||||
<button
|
||||
onClick={() => openUrl(p.prod_url!).catch(() => {})}
|
||||
className="flex items-center gap-1 text-xs px-2.5 py-1 rounded-md bg-emerald-50 text-emerald-700 border border-emerald-200 hover:bg-emerald-100 transition-colors"
|
||||
title={p.prod_url}
|
||||
>
|
||||
🌐 生产
|
||||
</button>
|
||||
)}
|
||||
{p.staging_url && (
|
||||
<button
|
||||
onClick={() => openUrl(p.staging_url!).catch(() => {})}
|
||||
className="flex items-center gap-1 text-xs px-2.5 py-1 rounded-md bg-amber-50 text-amber-700 border border-amber-200 hover:bg-amber-100 transition-colors"
|
||||
title={p.staging_url}
|
||||
>
|
||||
🧪 测试
|
||||
</button>
|
||||
)}
|
||||
{p.server_note && (
|
||||
<span className="text-xs text-gray-400 truncate" title={p.server_note}>
|
||||
🖥 {p.server_note}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* ── Git 状态栏 ── */}
|
||||
|
||||
@ -1057,6 +1057,12 @@ export interface IterationJump {
|
||||
rate_after: number;
|
||||
}
|
||||
|
||||
export interface ProjectNoteEntry {
|
||||
project_name: string;
|
||||
content: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface FlywheelStats {
|
||||
cohorts: FlywheelCohort[];
|
||||
top_blocked_reasons: BlockedReasonCount[];
|
||||
@ -1070,6 +1076,8 @@ export interface FlywheelStats {
|
||||
stalled_modules: string[];
|
||||
total_projects_scanned: number;
|
||||
projects_with_data: number;
|
||||
/** 跨项目复盘笔记(最近 50 条) */
|
||||
project_notes: ProjectNoteEntry[];
|
||||
}
|
||||
|
||||
export const getFlywheelStats = (projectPaths: string[]) =>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user