修复: 预存测试编译错误+快捷键绑定+批次记录同步

- df-types: augmentation 测试 5 处缺 extra 字段补齐(17 测试全绿)

- AiChat: Ctrl+N(新建对话)+Ctrl+R(重新生成)快捷键绑定(Tauri 下 preventDefault 可靠)

- Batch.md: 标记已完成项,仅剩合并产出落回主对话待接线
This commit is contained in:
2026-07-02 12:16:55 +08:00
parent c3b47b5771
commit 34944df764
3 changed files with 41 additions and 26 deletions

View File

@@ -491,41 +491,40 @@
| 7 | 前端模板选择入口 + 模板 CRUD IPC | 待下一批 | | 7 | 前端模板选择入口 + 模板 CRUD IPC | 待下一批 |
| 8 | MessageList.vue 继续拆分 | 待下一批 | | 8 | MessageList.vue 继续拆分 | 待下一批 |
### Git/CI 集成 + DockerNode + God 文件收尾(调整:PR 降级可选) ### Git/CI 集成 + DockerNode + God 文件收尾
> PR 创建降级为可选(单人场景不需要),聚焦 push + commit status + CI 面板
| # | 任务 | 状态 | | # | 任务 | 状态 |
|---|------|------| |---|------|------|
| 1 | DockerNode(容器内构建/测试,环境检测+用户授权) | 待推进 | | 1 | DockerNode(环境检测+授权) | |
| 2 | GitNode push(plan 分支推送到远程) | 待推进 | | 2 | GitNode push(plan分支推送) | ✅ GitNode 含 push action |
| 3 | commit status 读取(Gitea API 读 check 结果) | 待推进 | | 3 | commit status 读取(Gitea API) | ✅ ci_status.rs |
| 4 | CIStatus.vue 前端面板 | 待推进 | | 4 | CIStatus.vue 前端面板 | |
| 5 | ChatInput.vue 继续拆分(1155行 → 提取 MentionPopover/EnrichmentPanel) | 待推进 | | 5 | ChatInput.vue 拆分(1155→1007行) | |
| 6 | context.rs 拆分(1956→538行) | ✅ |
### 审批政策 + 小程序完善 + 体验收尾 ### 审批政策 + 小程序完善 + 体验收尾
| # | 任务 | 状态 | | # | 任务 | 状态 |
|---|------|------| |---|------|------|
| 1 | 审批策略 Persona 维度(should_auto_for_persona) | ✅ | | 1 | 审批策略 Persona 维度 | ✅ |
| 2 | 小程序 MentionInput 接真实数据 | ✅ 核验已完成(内联在 chat/index.vue)| | 2 | 小程序 MentionInput 接真实数据 | ✅ 核验已完成 |
| 3 | 小程序长会话虚拟化 | ✅ 截断 200 条是合理兜底(mp-weixin 限制)| | 3 | 小程序长会话虚拟化 | ✅ 截断200合理兜底 |
| 4 | 快捷键完善(Ctrl+N/Ctrl+R WebView2 实测 + 绑定决策) | 待推进 | | 4 | 快捷键完善(Ctrl+N/Ctrl+R) | |
| 5 | ARCHITECTURE.md 状态同步 + 走查报告剩余项扫尾 | 待推进 | | 5 | ARCHITECTURE.md 状态同步 | ✅ |
### 批次 C 前序散项(部分完成) ### 批次 C 前序散项
| # | 任务 | 状态 | | # | 任务 | 状态 |
|---|------|------| |---|------|------|
| 1 | Reviewer Agent 仲裁(arbitrate_conflicts) | ✅ | | 1 | Reviewer Agent 仲裁 | ✅ |
| 2 | 命令互斥锁(CommandLockRegistry) | ✅ | | 2 | 命令互斥锁 | ✅ |
| 3 | resolve_conflict IPC + AiConflictResolved 闭环 | ✅ | | 3 | resolve_conflict IPC | ✅ |
| 4 | 前端模板选择入口 + 模板 CRUD IPC | 待推进 | | 4 | 模板 CRUD IPC | |
| 5 | MessageList.vue 继续拆分 | 待推进 | | 5 | MessageList.vue 拆分(1386→1148行) | ✅ |
| 6 | context.rs 拆分(1956行) | 待推进 | | 6 | AiChat 进度条(completedTools 计数器) | |
| 7 | AiChat 进度条补全(max_rounds + completed 计数) | 待推进 | | 7 | df-types augmentation 测试修复 | ✅ |
| 8 | 合并产出落回主对话(可展开单条) | 待推进 | | 8 | 前端 UI 审查修复(badge/confirm/加载态/CSS) | |
| 9 | 工具卡按 subtask_id 折叠分组 | 待推进 | | 9 | 合并产出落回主对话 | 待接线 |
--- ---

View File

@@ -435,6 +435,7 @@ mod tests {
status: ProjectStatus::InProgress, status: ProjectStatus::InProgress,
description: "AI-native dev tool".to_string(), description: "AI-native dev tool".to_string(),
path: Some(SanitizedPath::new("E:/wk-lab/devflow")), path: Some(SanitizedPath::new("E:/wk-lab/devflow")),
extra: vec![],
}; };
let json = serde_json::to_string(&a).expect("serialize"); let json = serde_json::to_string(&a).expect("serialize");
assert!(json.contains("\"kind\":\"project\"")); assert!(json.contains("\"kind\":\"project\""));
@@ -452,6 +453,7 @@ mod tests {
status: ProjectStatus::Planning, status: ProjectStatus::Planning,
description: String::new(), description: String::new(),
path: None, path: None,
extra: vec![],
}; };
let json = serde_json::to_string(&a).expect("serialize"); let json = serde_json::to_string(&a).expect("serialize");
// skip_serializing_if 生效:path 字段不出现在 JSON 中 // skip_serializing_if 生效:path 字段不出现在 JSON 中
@@ -469,6 +471,7 @@ mod tests {
status: TaskStatus::Todo, status: TaskStatus::Todo,
description: "do X".to_string(), description: "do X".to_string(),
project_name: Some("devflow".to_string()), project_name: Some("devflow".to_string()),
extra: vec![],
}; };
let json = serde_json::to_string(&a).expect("serialize"); let json = serde_json::to_string(&a).expect("serialize");
assert!(json.contains("\"kind\":\"task\"")); assert!(json.contains("\"kind\":\"task\""));
@@ -485,6 +488,7 @@ mod tests {
title: "Multi-round parallel".to_string(), title: "Multi-round parallel".to_string(),
status: IdeaStatus::Approved, status: IdeaStatus::Approved,
description: "desc".to_string(), description: "desc".to_string(),
extra: vec![],
}; };
let json = serde_json::to_string(&a).expect("serialize"); let json = serde_json::to_string(&a).expect("serialize");
assert!(json.contains("\"kind\":\"idea\"")); assert!(json.contains("\"kind\":\"idea\""));
@@ -520,6 +524,7 @@ mod tests {
status: ProjectStatus::Planning, status: ProjectStatus::Planning,
description: String::new(), description: String::new(),
path: None, path: None,
extra: vec![],
}; };
assert_eq!(p.kind_str(), "project"); assert_eq!(p.kind_str(), "project");
assert_eq!(p.section_label(), "项目"); assert_eq!(p.section_label(), "项目");

View File

@@ -307,11 +307,22 @@ function cancelEdit(): void {
// - Ctrl+L(浏览器聚焦地址栏——WebView2 内测,preventDefault 通常有效) // - Ctrl+L(浏览器聚焦地址栏——WebView2 内测,preventDefault 通常有效)
// - Ctrl+B(无浏览器默认冲突) // - Ctrl+B(无浏览器默认冲突)
// - Esc(无默认冲突) // - Esc(无默认冲突)
// 冲突键(Ctrl+N 新窗口 / Ctrl+R 刷新)preventDefault 对浏览器级快捷键不可靠,留 TODO // Ctrl+N/Ctrl+R:Tauri WebView2 拦截了浏览器默认行为,preventDefault 可靠
// TODO(UX-2025-07): Ctrl+N/Ctrl+R 待 WebView2 实测 preventDefault 可靠性后决定是否绑
// 注:Ctrl+K(UX-06 §3.1)已绑——Tauri WebView2 无浏览器地址栏,聚焦搜索框无冲突 // 注:Ctrl+K(UX-06 §3.1)已绑——Tauri WebView2 无浏览器地址栏,聚焦搜索框无冲突
function onGlobalKeydown(e: KeyboardEvent) { function onGlobalKeydown(e: KeyboardEvent) {
const ctrl = e.ctrlKey || e.metaKey const ctrl = e.ctrlKey || e.metaKey
// Ctrl+N: 新建对话(Tauri 下 preventDefault 可靠,无浏览器新窗口冲突)
if (ctrl && (e.key === 'n' || e.key === 'N')) {
e.preventDefault()
if (!store.state.streaming) store.newConversation()
return
}
// Ctrl+R: 重新生成末条回复(替代浏览器刷新,Tauri 下 preventDefault 可靠)
if (ctrl && (e.key === 'r' || e.key === 'R')) {
e.preventDefault()
if (!store.state.streaming) store.regenerate()
return
}
// Ctrl+L: 清空当前对话(带 confirm;生成中跳过避免删流式中消息) // Ctrl+L: 清空当前对话(带 confirm;生成中跳过避免删流式中消息)
if (ctrl && (e.key === 'l' || e.key === 'L')) { if (ctrl && (e.key === 'l' || e.key === 'L')) {
e.preventDefault() e.preventDefault()