重构: df-core改名df-types(类型库语义准+全workspace机械改名54处)

This commit is contained in:
2026-06-17 02:44:34 +08:00
parent a19f535134
commit 4be15912cd
40 changed files with 90 additions and 90 deletions

38
Cargo.lock generated
View File

@@ -741,12 +741,12 @@ dependencies = [
"base64 0.22.1",
"chrono",
"df-ai",
"df-core",
"df-execute",
"df-ideas",
"df-nodes",
"df-project",
"df-storage",
"df-types",
"df-workflow",
"futures",
"keyring",
@@ -768,7 +768,7 @@ dependencies = [
"anyhow",
"async-trait",
"df-ai-core",
"df-core",
"df-types",
"eventsource-stream",
"futures",
"reqwest 0.12.28",
@@ -789,24 +789,13 @@ dependencies = [
"serde_json",
]
[[package]]
name = "df-core"
version = "0.1.0"
dependencies = [
"chrono",
"serde",
"serde_json",
"thiserror 2.0.18",
"uuid",
]
[[package]]
name = "df-execute"
version = "0.1.0"
dependencies = [
"anyhow",
"async-trait",
"df-core",
"df-types",
"serde",
"serde_json",
"tokio",
@@ -822,7 +811,7 @@ dependencies = [
"chrono",
"df-ai",
"df-ai-core",
"df-core",
"df-types",
"regex",
"serde",
"serde_json",
@@ -837,9 +826,9 @@ dependencies = [
"anyhow",
"async-trait",
"df-ai",
"df-core",
"df-execute",
"df-storage",
"df-types",
"df-workflow",
"serde",
"serde_json",
@@ -853,7 +842,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"df-core",
"df-types",
"serde",
"serde_json",
"tokio",
@@ -866,7 +855,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"df-ai-core",
"df-core",
"df-types",
"keyring",
"rusqlite",
"serde",
@@ -875,13 +864,24 @@ dependencies = [
"tracing",
]
[[package]]
name = "df-types"
version = "0.1.0"
dependencies = [
"chrono",
"serde",
"serde_json",
"thiserror 2.0.18",
"uuid",
]
[[package]]
name = "df-workflow"
version = "0.1.0"
dependencies = [
"anyhow",
"async-trait",
"df-core",
"df-types",
"futures",
"serde",
"serde_json",

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
df-core = { path = "../df-core" }
df-types = { path = "../df-types" }
df-ai-core = { path = "../df-ai-core" }
serde = { workspace = true }
serde_json = { workspace = true }

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
df-core = { path = "../df-core" }
df-types = { path = "../df-types" }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
df-core = { path = "../df-core" }
df-types = { path = "../df-types" }
df-ai-core = { path = "../df-ai-core" }
# F-01 阶段5: df-ideas 对抗评估接入 df_ai::router::select_model_id(纯函数路由)。
# 注:df-ai 引入 reqwest/futures/eventsource-stream 重依赖,但 router 模块仅依赖

View File

@@ -18,7 +18,7 @@ use serde::{Deserialize, Serialize};
use df_ai_core::model::ModelConfig;
use df_ai_core::provider::LlmProvider;
use df_core::types::{IdeaId, Priority};
use df_types::types::{IdeaId, Priority};
use crate::capture::Idea;
use crate::scoring::IdeaScores;
@@ -653,7 +653,7 @@ mod tests {
use super::*;
use crate::capture::Idea;
use crate::scoring::ScoringEngine;
use df_core::types::{IdeaStatus, Priority};
use df_types::types::{IdeaStatus, Priority};
fn make_idea(title: &str, desc: &str, priority: Priority, tags: Vec<&str>) -> Idea {
Idea {

View File

@@ -2,7 +2,7 @@
use serde::{Deserialize, Serialize};
use df_core::types::{IdeaId, Priority};
use df_types::types::{IdeaId, Priority};
/// 想法实体
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -14,7 +14,7 @@ pub struct Idea {
/// 详细描述
pub description: String,
/// 当前状态
pub status: df_core::types::IdeaStatus,
pub status: df_types::types::IdeaStatus,
/// 优先级
pub priority: Priority,
/// 评分

View File

@@ -10,7 +10,7 @@
use serde::Serialize;
use df_core::types::{IdeaId, ProjectId};
use df_types::types::{IdeaId, ProjectId};
/// 晋升结果promote_idea IPC 返回类型)
#[derive(Debug, Clone, Serialize)]

View File

@@ -9,7 +9,7 @@ use crate::capture::Idea;
/// 想法评分详情(重新导出 capture 模块中的定义)
pub use crate::capture::IdeaScores;
use df_core::types::Priority;
use df_types::types::Priority;
/// 评分权重配置
#[derive(Debug, Clone)]
@@ -135,7 +135,7 @@ fn count_any(text: &str, keywords: &[&str]) -> usize {
mod tests {
use super::*;
use crate::capture::Idea;
use df_core::types::{IdeaStatus, Priority};
use df_types::types::{IdeaStatus, Priority};
/// 辅助工厂:构造测试用 Idea时间/ID 用默认值,不影响评分)
fn make_idea(title: &str, desc: &str, priority: Priority, tags: Vec<&str>) -> Idea {

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
df-core = { path = "../df-core" }
df-types = { path = "../df-types" }
df-execute = { path = "../df-execute" }
df-workflow = { path = "../df-workflow" }
df-ai = { path = "../df-ai" }

View File

@@ -565,7 +565,7 @@ impl Node for AiSelfReviewNode {
};
review_with_meta.insert(
"reviewed_at".into(),
serde_json::Value::Number(df_core::now_millis().into()),
serde_json::Value::Number(df_types::now_millis().into()),
);
review_with_meta.insert("reviewer_model".into(), serde_json::json!(response.model));
output_obj.insert("review".into(), serde_json::Value::Object(review_with_meta));

View File

@@ -4,7 +4,7 @@ use async_trait::async_trait;
use std::time::Duration;
use tokio::sync::broadcast;
use df_workflow::node::{Node, NodeContext, NodeOutput, NodeResult, NodeSchema};
use df_core::events::{SelectType, WorkflowEvent};
use df_types::events::{SelectType, WorkflowEvent};
/// F-260616-06 阶段2: 拒绝语义化关键字。
/// decision 归一化(去空白 + 小写)后命中此集合 → 审批拒绝 → 节点返 Err(触发工作流 failed)。
@@ -217,7 +217,7 @@ impl Node for HumanNode {
#[cfg(test)]
mod tests {
use super::*;
use df_core::types::NodeStatus;
use df_types::types::NodeStatus;
use df_workflow::dag::Dag;
use df_workflow::eventbus::EventBus;
use df_workflow::executor::DagExecutor;

View File

@@ -44,10 +44,10 @@ pub async fn advance_task_atomic(
repo: &TaskRepo,
id: &str,
target_status: &str,
) -> df_core::error::Result<TaskRecord> {
) -> df_types::error::Result<TaskRecord> {
// 1. target 合法性(7 态之一)。先于读库校验:即便任务不存在,也先拒绝非法状态值。
if !is_valid_state(target_status) {
return Err(df_core::error::Error::Validation(format!(
return Err(df_types::error::Error::Validation(format!(
"非法 target_status {:?},合法值: {}",
target_status,
ALL_STATES.join("/")
@@ -58,19 +58,19 @@ pub async fn advance_task_atomic(
let current = repo
.get_by_id(id)
.await?
.ok_or_else(|| df_core::error::Error::NotFound(format!("任务 {} 不存在", id)))?;
.ok_or_else(|| df_types::error::Error::NotFound(format!("任务 {} 不存在", id)))?;
// 3. 状态机校验(三类拒绝,错误类型区分供前端分辨):
// - 同态(from==to):Validation「相同状态,无需推进」(空操作,非状态机违例)
// - 非法转换(跳态/终态无后继等):InvalidState「非法状态转换 X→Y」
let from = current.status.as_str();
if from == target_status {
return Err(df_core::error::Error::Validation(format!(
return Err(df_types::error::Error::Validation(format!(
"相同状态 {from:?},无需推进"
)));
}
if !can_transition(from, target_status) {
return Err(df_core::error::Error::InvalidState {
return Err(df_types::error::Error::InvalidState {
current: format!("{from}→{target_status}(非法状态转换)"),
expected: target_status.to_string(),
});
@@ -83,7 +83,7 @@ pub async fn advance_task_atomic(
.await?;
// 5. CAS 失败:并发已改动 status(或任务被删),拒绝静默成功。
updated.ok_or_else(|| df_core::error::Error::InvalidState {
updated.ok_or_else(|| df_types::error::Error::InvalidState {
current: "已变更(并发推进或旁路修改)".to_string(),
expected: from.to_string(),
})
@@ -268,7 +268,7 @@ mod tests {
repo.insert(rec("t1", "todo")).await.unwrap();
let err = advance_task_atomic(&repo, "t1", "done").await.unwrap_err();
match err {
df_core::error::Error::InvalidState { current, expected } => {
df_types::error::Error::InvalidState { current, expected } => {
assert!(current.contains("todo→done"), "非法转换消息应含 from→to,实际: {current}");
assert!(current.contains("非法状态转换"), "消息应含「非法状态转换」,实际: {current}");
assert_eq!(expected, "done");
@@ -284,7 +284,7 @@ mod tests {
repo.insert(rec("t1", "done")).await.unwrap();
let err = advance_task_atomic(&repo, "t1", "todo").await.unwrap_err();
match err {
df_core::error::Error::InvalidState { current, .. } => {
df_types::error::Error::InvalidState { current, .. } => {
assert!(current.contains("done→todo"), "终态后继消息应含 from→to,实际: {current}");
}
other => panic!("终态后继应是 InvalidState,实际: {other:?}"),
@@ -300,7 +300,7 @@ mod tests {
repo.insert(rec("t1", "in_progress")).await.unwrap();
let err = advance_task_atomic(&repo, "t1", "in_progress").await.unwrap_err();
match err {
df_core::error::Error::Validation(msg) => {
df_types::error::Error::Validation(msg) => {
assert!(msg.contains("相同状态"), "同态消息应含「相同状态」,实际: {msg}");
}
other => panic!("同态拒绝应是 Validation,实际: {other:?}"),
@@ -312,14 +312,14 @@ mod tests {
let repo = setup().await;
repo.insert(rec("t1", "todo")).await.unwrap();
let err = advance_task_atomic(&repo, "t1", "merged").await.unwrap_err();
assert!(matches!(err, df_core::error::Error::Validation(_)));
assert!(matches!(err, df_types::error::Error::Validation(_)));
}
#[tokio::test]
async fn not_found_rejected() {
let repo = setup().await;
let err = advance_task_atomic(&repo, "nope", "in_progress").await.unwrap_err();
assert!(matches!(err, df_core::error::Error::NotFound(_)));
assert!(matches!(err, df_types::error::Error::NotFound(_)));
}
#[tokio::test]

View File

@@ -1,10 +1,10 @@
//! 任务推进状态机 — 7 态合法转换定义(F-260616-01)
//!
//! 独立模块,非挂在 df-core::TaskStatus enum 上(对齐 D-260616-03「推进链业务逻辑落
//! 独立模块,非挂在 df-types::TaskStatus enum 上(对齐 D-260616-03「推进链业务逻辑落
//! df-nodes」)。本模块只做「给定 from/to 是否合法」的纯函数判定,不触碰存储层
//! (原子写 SQL 在 task_advance_node.rs 完成,见 F-260616-02)。
//!
//! 7 态(与 df-core::TaskStatus / 前端对齐,D-260616-01):
//! 7 态(与 df-types::TaskStatus / 前端对齐,D-260616-01):
//! todo / in_progress / in_review / testing / done / blocked / cancelled
//!
//! 闸门链主路径: todo → in_progress → in_review → testing → done
@@ -22,11 +22,11 @@
//! - cancelled → 终态
// ============================================================
// 状态字符串常量 — 与 df-core::TaskStatus::as_str 一一对应
// 状态字符串常量 — 与 df-types::TaskStatus::as_str 一一对应
// ============================================================
//
// 不复用 df-core::TaskStatus enum(独立模块定位 + 避免推进链判定耦合存储枚举类型),
// 但字符串值严格对齐(df-core::TaskStatus::as_str 产出的小写 snake_case),
// 不复用 df-types::TaskStatus enum(独立模块定位 + 避免推进链判定耦合存储枚举类型),
// 但字符串值严格对齐(df-types::TaskStatus::as_str 产出的小写 snake_case),
// 保证状态机判定的 from/to 与数据库 status 列存值语义一致。
/// 待开始

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
df-core = { path = "../df-core" }
df-types = { path = "../df-types" }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }

View File

@@ -2,7 +2,7 @@
use serde::{Deserialize, Serialize};
use df_core::types::{IdeaId, Priority, ProjectId, ProjectStatus};
use df_types::types::{IdeaId, Priority, ProjectId, ProjectStatus};
/// 项目实体
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -49,7 +49,7 @@ impl ProjectManager {
pub fn create(input: CreateProjectInput) -> Project {
let now = chrono::Utc::now();
Project {
id: df_core::types::new_id(),
id: df_types::types::new_id(),
name: input.name,
description: input.description,
status: ProjectStatus::Planning,

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
df-core = { path = "../df-core" }
df-types = { path = "../df-types" }
# F-01 阶段1:ModelConfig/deserialize_model_configs 向后兼容反序列化(老字符串数组/新对象数组/null/空)
df-ai-core = { path = "../df-ai-core" }
serde = { workspace = true }

View File

@@ -7,7 +7,7 @@ use std::sync::Arc;
use rusqlite::{params, Connection, OptionalExtension, Row};
use tokio::sync::Mutex;
use df_core::error::{Error, Result};
use df_types::error::{Error, Result};
use crate::db::Database;
use crate::models::{
@@ -16,7 +16,7 @@ use crate::models::{
TaskRecord, WorkflowRecord,
};
/// rusqlite 错误 → df-core `Error::Storage` 统一包装(R-PD-10 DRY,
/// rusqlite 错误 → df-types `Error::Storage` 统一包装(R-PD-10 DRY,
/// 替代散落的 `.map_err(storage_err)`)。
fn storage_err<E: std::string::ToString>(e: E) -> Error {
Error::Storage(e.to_string())
@@ -412,8 +412,8 @@ pub fn is_allowed_column(table: &str, field: &str) -> bool {
// ============================================================
fn now_millis_str() -> String {
// 转发 df_core::now_millis(DRY:时间获取统一入口在 df-core,避免本 crate 与 commands 层各写一份 SystemTime 调用)
df_core::now_millis().to_string()
// 转发 df_types::now_millis(DRY:时间获取统一入口在 df-types,避免本 crate 与 commands 层各写一份 SystemTime 调用)
df_types::now_millis().to_string()
}
// ============================================================

View File

@@ -1,5 +1,5 @@
[package]
name = "df-core"
name = "df-types"
version = "0.1.0"
edition = "2021"

View File

@@ -1,8 +1,8 @@
//! df-core: 核心类型定义,所有 crate 的基础依赖
//! df-types: 核心类型定义,所有 crate 的基础依赖
pub mod error;
pub mod events;
pub mod types;
// 顶层 re-export:常用时间工具(跨 crate 调用方用 df_core::now_millis,避免 types:: 前缀)
// 顶层 re-export:常用时间工具(跨 crate 调用方用 df_types::now_millis,避免 types:: 前缀)
pub use types::now_millis;

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
df-core = { path = "../df-core" }
df-types = { path = "../df-types" }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }

View File

@@ -2,8 +2,8 @@
use std::collections::{HashMap, HashSet, VecDeque};
use df_core::error::Result;
use df_core::types::NodeId;
use df_types::error::Result;
use df_types::types::NodeId;
use crate::node::Node;
@@ -141,7 +141,7 @@ impl Dag {
}
if processed != node_ids.len() {
return Err(df_core::error::Error::Workflow(
return Err(df_types::error::Error::Workflow(
"DAG 中存在环,无法进行拓扑排序".to_string(),
));
}

View File

@@ -2,7 +2,7 @@
use tokio::sync::broadcast;
use tokio::sync::broadcast::error::SendError;
use df_core::events::WorkflowEvent;
use df_types::events::WorkflowEvent;
/// 事件总线
#[derive(Debug)]

View File

@@ -2,8 +2,8 @@
use std::collections::HashMap;
use df_core::events::WorkflowEvent;
use df_core::types::NodeId;
use df_types::events::WorkflowEvent;
use df_types::types::NodeId;
use crate::dag::Dag;
use crate::eventbus::EventBus;
@@ -350,7 +350,7 @@ mod tests {
assert!(err.to_string().contains("节点 a 执行失败"));
// 同层成功节点状态正常更新,下游节点保持 Pending
use df_core::types::NodeStatus;
use df_types::types::NodeStatus;
assert_eq!(executor.state_machine.get(&"a".to_string()), NodeStatus::Failed);
assert_eq!(executor.state_machine.get(&"b".to_string()), NodeStatus::Completed);
assert_eq!(executor.state_machine.get(&"c".to_string()), NodeStatus::Pending);
@@ -383,7 +383,7 @@ mod tests {
/// 状态保持 Cancelled,run 返回取消相关 Err 而非状态转换错误。
#[tokio::test]
async fn test_cancelled_node_skips_set_failed() {
use df_core::types::NodeStatus;
use df_types::types::NodeStatus;
let mut dag = Dag::new();
dag.add_node("x".to_string(), Box::new(CancelSelfNode));
@@ -434,7 +434,7 @@ mod tests {
/// 状态保持 Cancelled,run 返回 Ok(已批准审批不应误报失败)。
#[tokio::test]
async fn test_cancelled_node_skips_set_completed() {
use df_core::types::NodeStatus;
use df_types::types::NodeStatus;
let mut dag = Dag::new();
dag.add_node("y".to_string(), Box::new(CancelSelfThenOkNode));
@@ -458,8 +458,8 @@ mod tests {
/// 前端按 type 区分「取消」与「失败」。订阅事件总线收集所有事件断言。
#[tokio::test]
async fn test_cancelled_node_emits_node_cancelled_event() {
use df_core::events::WorkflowEvent;
use df_core::types::NodeStatus;
use df_types::events::WorkflowEvent;
use df_types::types::NodeStatus;
let mut dag = Dag::new();
dag.add_node("c".to_string(), Box::new(CancelSelfNode));

View File

@@ -3,7 +3,7 @@
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use df_core::types::NodeId;
use df_types::types::NodeId;
use super::eventbus::EventBus;
use super::state::StateMachine;

View File

@@ -12,7 +12,7 @@
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use df_core::types::{NodeId, NodeStatus};
use df_types::types::{NodeId, NodeStatus};
/// 节点状态机
#[derive(Debug, Clone)]

View File

@@ -25,7 +25,7 @@ tracing.workspace = true
chrono.workspace = true
# 后端 crate
df-core = { path = "../crates/df-core" }
df-types = { path = "../crates/df-types" }
df-storage = { path = "../crates/df-storage" }
df-workflow = { path = "../crates/df-workflow" }
df-nodes = { path = "../crates/df-nodes" }

View File

@@ -12,7 +12,7 @@ use df_storage::crud::{AiToolExecutionRepo, ProjectRepo};
use df_storage::db::Database;
use df_storage::models::AiToolExecutionRecord;
use df_core::types::new_id;
use df_types::types::new_id;
use crate::state::AppState;

View File

@@ -8,7 +8,7 @@ use tauri::{AppHandle, Emitter, State};
use df_ai::provider::ChatMessage;
// df-ai 重导出 df_ai_core(供下游直接引用 trait/类型);src-tauri 不直接依赖 df-ai-core crate。
use df_ai::df_ai_core::model::ModelConfig;
use df_core::types::new_id;
use df_types::types::new_id;
use df_storage::models::AiProviderRecord;
use crate::state::AppState;

View File

@@ -16,7 +16,7 @@ use df_storage::crud::{AiConversationRepo, KnowledgeRepo};
use df_storage::db::Database;
use df_storage::models::{AiProviderRecord, KnowledgeRecord};
use df_core::types::new_id;
use df_types::types::new_id;
use crate::state::{AppState, ExtractTrigger, LlmConcurrency};

View File

@@ -11,7 +11,7 @@ use df_execute::shell::{execute, ShellRequest};
use df_storage::db::Database;
use df_storage::models::{ProjectRecord, TaskRecord, IdeaRecord};
use df_core::types::new_id;
use df_types::types::new_id;
use crate::commands::now_millis;

View File

@@ -6,7 +6,7 @@ use serde::Deserialize;
use tauri::State;
use df_ai::provider::LlmProvider;
use df_core::types::{new_id, Priority};
use df_types::types::{new_id, Priority};
use df_ideas::capture::Idea;
use df_storage::models::{IdeaRecord, ProjectRecord};
@@ -298,7 +298,7 @@ fn record_to_idea(record: &IdeaRecord) -> Idea {
id: record.id.clone(),
title: record.title.clone(),
description: record.description.clone(),
status: df_core::types::IdeaStatus::Draft,
status: df_types::types::IdeaStatus::Draft,
priority: priority_from_i32(record.priority),
scores: None,
tags,
@@ -309,7 +309,7 @@ fn record_to_idea(record: &IdeaRecord) -> Idea {
}
}
/// i32 优先级 → Priority 枚举(与 df-core 枚举值一致Low=0/Medium=1/High=2/Critical=3
/// i32 优先级 → Priority 枚举(与 df-types 枚举值一致Low=0/Medium=1/High=2/Critical=3
fn priority_from_i32(p: i32) -> Priority {
match p {
0 => Priority::Low,

View File

@@ -6,7 +6,7 @@
use serde::Deserialize;
use tauri::State;
use df_core::types::new_id;
use df_types::types::new_id;
use df_storage::models::{KnowledgeEventRecord, KnowledgeRecord};
use crate::state::{AppState, KnowledgeConfig};

View File

@@ -7,7 +7,7 @@
use std::sync::Arc;
use df_core::types::new_id;
use df_types::types::new_id;
use df_storage::crud::KnowledgeEventsRepo;
use df_storage::db::Database;
use df_storage::models::KnowledgeEventRecord;

View File

@@ -13,9 +13,9 @@ pub mod workflow;
/// 当前时间戳(毫秒字符串)— 与 df-storage 内部的时间格式保持一致
///
/// 转发 df_core::now_millis(DRY:时间获取统一入口在此 crate,避免 commands 层与 df-storage 各写一份 SystemTime 调用)。
/// 转发 df_types::now_millis(DRY:时间获取统一入口在此 crate,避免 commands 层与 df-storage 各写一份 SystemTime 调用)。
pub(crate) fn now_millis() -> String {
df_core::now_millis().to_string()
df_types::now_millis().to_string()
}
/// .map_err 错误格式化统一入口 — 当前行为零变化(仅 e.to_string()),

View File

@@ -11,7 +11,7 @@ use df_ai::provider::{ChatMessage, CompletionRequest};
use df_ai::router::{
select_model_id, IntelligenceTier, Modality, TaskRequirements,
};
use df_core::types::new_id;
use df_types::types::new_id;
use df_project::scan::{
collect_sample, detect_stack, discover_projects, extract_description, is_monorepo,
normalize_path, DiscoveredProject,

View File

@@ -3,7 +3,7 @@
use serde::Deserialize;
use tauri::State;
use df_core::types::{new_id, TaskStatus};
use df_types::types::{new_id, TaskStatus};
use df_storage::models::TaskRecord;
use crate::state::AppState;

View File

@@ -7,8 +7,8 @@ use serde::Serialize;
use tauri::{AppHandle, Emitter, State};
use tokio::sync::broadcast::error::RecvError;
use df_core::events::{WorkflowEvent, HumanApprovalResponse, SelectType};
use df_core::types::{new_id, NodeStatus};
use df_types::events::{WorkflowEvent, HumanApprovalResponse, SelectType};
use df_types::types::{new_id, NodeStatus};
use df_nodes::task_advance_node::advance_task_atomic;
// F-260616-06 ①-1: 空 dag + target_status 时按目标态自动选推进链模板
use df_nodes::task_workflow_templates::template_for;