Files
DevFlow/src-tauri/src/lib.rs
绝尘 8da6bdcec2 新增: AI 工具意图识别层 + 文件访问权限模型 Phase B+C
会话意图识别层(intent.rs / df-ai crate):
- Intent 枚举 11 态 + recognize 规则识别(关键词+权重+优先级)+ tool_subset_for 工具子集映射
- 模态接口预留 None,独立模块待接入 loop,36 单测

文件访问权限模型 Phase B+C(F-260619-03):
- Phase B 会话临时白名单 + 循环挂起 + DirAuthDialog 弹窗(仅本次/未来都允许/拒绝)
- Phase C 系统目录黑名单(Win System32/Program Files;Unix /etc /usr...)分段匹配 + 写操作约束
- 已审 CR-260619-09  PASS
2026-06-19 18:58:48 +08:00

198 lines
9.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! DevFlow Tauri 入口 — 初始化 AppState 并注册全部 IPC 命令
mod commands;
mod state;
use tauri::{Emitter, Listener, Manager};
use state::AppState;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_window_state::Builder::default().build())
.setup(|app| {
// 数据库放在系统应用数据目录 <app_data_dir> 下dev/release 拆分):
// Dev 模式 devflow-dev.db可随意改动/清空Build 模式 devflow.db长期保留真实运行数据
let db_name = if cfg!(debug_assertions) { "devflow-dev.db" } else { "devflow.db" };
let data_dir = app.path().app_data_dir()?;
std::fs::create_dir_all(&data_dir)?;
let db_path = data_dir.join(db_name);
// 初始化全局状态(打开数据库 + 执行迁移)
let app_state = tauri::async_runtime::block_on(AppState::init(&db_path))?;
// FR-S1:启动一次性迁移 DB 明文 api_key → OS keyring(失败保留明文下次重试,非阻断)
if let Err(e) = tauri::async_runtime::block_on(
commands::ai::secret::migrate_secrets_to_keyring(&app_state.ai_providers),
) {
tracing::warn!("[FR-S1] 启动密钥迁移失败(非阻断): {}", e);
}
// B-260616-01: L0 握手 — 提前 clone ai_session(Arc),因 manage() 会 move app_state
let session_for_handshake = app_state.ai_session.clone();
app.manage(app_state);
// B-260616-01: L0 握手 — 监听前端就绪事件,清除 HMR/刷新导致的残留 generating 状态
let app_handle = app.handle().clone();
app.listen("ai-client-ready", move |_event| {
let session_arc = session_for_handshake.clone();
let app_h = app_handle.clone();
tauri::async_runtime::spawn(async move {
let mut session = session_arc.lock().await;
// F-260616-09 B 批8(设计 §3 batch8 + §5.2):遍历 per_conv(HashMap)清多 conv
// 残留 generating(HMR/dev 热载场景多 conv 并发跑 loop 致多 conv 卡 generating)。
// 批4:per_conv 唯一真相源,删顶层 session.generating 双写复位(顶层字段已退役)。
let dirty_convs: Vec<String> = session
.per_conv
.iter()
.filter(|(_, c)| c.generating)
.map(|(id, _)| id.clone())
.collect();
let was_generating = !dirty_convs.is_empty();
// 复位每个残留 generating 的 conv(批8 多 conv 全覆盖)。
for cid in &dirty_convs {
if let Some(conv) = session.per_conv.get_mut(cid) {
conv.generating = false;
}
}
// BUG-260619-06 修复: clear 致冷启动 restore 重建审批丢失(restore 填充后 clear 无条件清空,
// 重启后待审批工具全丢)。改 retain 仅清非 recovered(本次会话/HMR 死 pending),
// 保留 restore 重建(recovered=true,audit.rs:331),对齐 switchConversation retain 保护意图。
session.pending_approvals.retain(|_, a| !a.recovered);
drop(session);
if was_generating {
// 补偿事件:每个残留 conv 各发一个 AiCompleted(按 conversation_id 路由),
// 前端 useAiEvents.ts:133-140 按 conv_id 各归各复位 streaming/generatingConvId。
for cid in &dirty_convs {
let _ = app_h.emit(
"ai-chat-event",
commands::ai::AiChatEvent::AiCompleted {
total_tokens: 0,
prompt_tokens: 0,
completion_tokens: 0,
incomplete: None,
conversation_id: Some(cid.clone()),
},
);
}
}
tracing::info!(
"[L0-handshake] 前端重连握手完成, was_generating={}, dirty_convs={:?}",
was_generating,
dirty_convs
);
});
});
Ok(())
})
.invoke_handler(tauri::generate_handler![
// 项目
commands::project::list_projects,
commands::project::create_project,
commands::project::import_project,
commands::project::get_project,
commands::project::update_project,
commands::project::delete_project,
commands::project::list_deleted_projects,
commands::project::restore_project,
commands::project::purge_project,
commands::project::scan_project_stack,
commands::project::check_path_binding,
commands::project::relocate_project_path,
commands::project::check_path_exists,
commands::project::scan_project_with_ai,
commands::project::scan_directory_for_projects,
commands::project::import_projects_batch,
// 任务
commands::task::list_tasks,
commands::task::create_task,
commands::task::update_task,
commands::task::delete_task,
commands::task::restore_task,
commands::task::get_task_by_id,
commands::task::advance_task,
// 灵感
commands::idea::list_ideas,
commands::idea::create_idea,
commands::idea::update_idea,
commands::idea::delete_idea,
commands::idea::evaluate_idea,
commands::idea::promote_idea,
// 工作流
commands::workflow::run_workflow,
commands::workflow::list_workflow_executions,
commands::workflow::get_workflow_execution,
commands::workflow::approve_human_approval,
commands::workflow::cancel_workflow_node,
// AI 聊天
commands::ai::ai_chat_send,
commands::ai::ai_regenerate,
commands::ai::ai_chat_edit,
commands::ai::ai_chat_force_send,
commands::ai::ai_chat_stop,
commands::ai::ai_approve,
// F-260616-03达 max_iterations 暂停态续/停(消费 AiMaxRoundsReached前端操作卡留 batch45
commands::ai::ai_continue_loop,
commands::ai::ai_stop_loop,
commands::ai::ai_pending_tool_calls,
commands::ai::ai_chat_clear,
commands::ai::ai_is_generating,
// F-15 阶段2 手动上下文管理:分段归档 + LLM 压缩
commands::ai::ai_chat_clear_context,
commands::ai::ai_chat_compress_context,
commands::ai::ai_list_providers,
commands::ai::ai_save_provider,
commands::ai::ai_set_provider,
commands::ai::ai_delete_provider,
// F-260614-04c: 负载均衡池可编辑层(enabled/weight 轻量更新 + caps 重建)
commands::ai::ai_update_provider_pool,
// F-01 阶段5:测试连接拉取模型列表 + 单模型探测
commands::ai::ai_fetch_models,
commands::ai::ai_probe_model,
// AI 对话管理
commands::ai::ai_conversation_create,
commands::ai::ai_conversation_list,
commands::ai::ai_conversation_switch,
commands::ai::ai_conversation_delete,
commands::ai::ai_conversation_rename,
commands::ai::ai_conversation_archive,
commands::ai::ai_conversation_set_pinned,
commands::ai::ai_conversation_export,
commands::ai::ai_list_skills,
commands::ai::ai_set_concurrency_config,
commands::ai::ai_set_agent_max_iterations,
commands::ai::ai_set_agent_max_retries,
// F-260619-03 Phase A: AI 工具文件访问授权目录白名单
commands::ai::ai_get_allowed_dirs,
commands::ai::ai_set_allowed_dirs,
// F-260619-03 Phase B: 路径授权弹窗决策(消费 AiDirAuthRequired 挂起)
commands::ai::ai_authorize_dir,
// 审批历史面板(AE-2025-08:查 ai_tool_executions 表,敏感字段截断)
commands::ai::audit::list_tool_executions,
// 知识库
commands::knowledge::knowledge_list,
commands::knowledge::knowledge_get,
commands::knowledge::knowledge_search,
commands::knowledge::knowledge_create,
commands::knowledge::knowledge_update_status,
commands::knowledge::knowledge_record_reuse,
commands::knowledge::knowledge_list_candidates,
commands::knowledge::knowledge_archive,
commands::knowledge::knowledge_get_config,
commands::knowledge::knowledge_save_config,
commands::knowledge::knowledge_extract_now,
commands::knowledge::knowledge_get_detail,
commands::knowledge::knowledge_update,
commands::knowledge::knowledge_events,
// 通用应用设置 KV(前端 localStorage 迁移目标)
commands::settings::settings_get,
commands::settings::settings_set,
commands::settings::settings_get_all,
commands::settings::settings_delete,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}