casting_cli/
tool_config.rs

1use serde::{Deserialize, Serialize};
2use version_migrate::migrator;
3use version_migrate::DeriveQueryable as Queryable;
4use version_migrate::{IntoDomain, MigratesTo, Migrator, Versioned};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7#[serde(tag = "type", rename_all = "lowercase")]
8pub enum ToolType {
9    Cli { bin_path: String },
10    Api { spec_url: String, base_url: String },
11    Expert,
12    Kaiba { profile: String },
13}
14
15// Version 1.0.0 - Old format with direct bin_path
16#[derive(Debug, Serialize, Deserialize, Versioned)]
17#[versioned(version = "1.0.0")]
18pub struct ToolConfigV1 {
19    pub tool_name: String,
20    pub bin_path: String,
21    pub persona: Option<String>,
22    pub created_at: String,
23}
24
25// Version 2.0.0 - New format with ToolType
26#[derive(Debug, Serialize, Deserialize, Versioned)]
27#[versioned(version = "2.0.0")]
28pub struct ToolConfigV2 {
29    pub tool_name: String,
30    #[serde(flatten)]
31    pub tool_type: ToolType,
32    pub persona: Option<String>,
33    pub created_at: String,
34}
35
36// Version 3.0.0 - Added aliases support
37#[derive(Debug, Serialize, Deserialize, Versioned)]
38#[versioned(version = "3.0.0")]
39pub struct ToolConfigV3 {
40    pub tool_name: String,
41    #[serde(flatten)]
42    pub tool_type: ToolType,
43    pub persona: Option<String>,
44    #[serde(default)]
45    pub aliases: Vec<String>,
46    pub created_at: String,
47}
48
49// Domain model (current ToolConfig)
50#[derive(Debug, Serialize, Deserialize, Queryable)]
51#[queryable(entity = "tool_config")]
52pub struct ToolConfig {
53    pub tool_name: String,
54    #[serde(flatten)]
55    pub tool_type: ToolType,
56    pub persona: Option<String>,
57    #[serde(default)]
58    pub aliases: Vec<String>,
59    pub created_at: String,
60}
61
62// Migration: V1 -> V2
63impl MigratesTo<ToolConfigV2> for ToolConfigV1 {
64    fn migrate(self) -> ToolConfigV2 {
65        ToolConfigV2 {
66            tool_name: self.tool_name,
67            tool_type: ToolType::Cli {
68                bin_path: self.bin_path,
69            },
70            persona: self.persona,
71            created_at: self.created_at,
72        }
73    }
74}
75
76// Migration: V2 -> V3
77impl MigratesTo<ToolConfigV3> for ToolConfigV2 {
78    fn migrate(self) -> ToolConfigV3 {
79        ToolConfigV3 {
80            tool_name: self.tool_name,
81            tool_type: self.tool_type,
82            persona: self.persona,
83            aliases: Vec::new(), // Existing configs have no aliases
84            created_at: self.created_at,
85        }
86    }
87}
88
89// Conversion: V3 -> Domain
90impl IntoDomain<ToolConfig> for ToolConfigV3 {
91    fn into_domain(self) -> ToolConfig {
92        ToolConfig {
93            tool_name: self.tool_name,
94            tool_type: self.tool_type,
95            persona: self.persona,
96            aliases: self.aliases,
97            created_at: self.created_at,
98        }
99    }
100}
101
102impl version_migrate::FromDomain<ToolConfig> for ToolConfigV3 {
103    fn from_domain(config: ToolConfig) -> Self {
104        ToolConfigV3 {
105            tool_name: config.tool_name,
106            tool_type: config.tool_type,
107            persona: config.persona,
108            aliases: config.aliases,
109            created_at: config.created_at,
110        }
111    }
112}
113
114/// Setup migrator for ToolConfig versioning
115pub fn setup_config_migrator() -> anyhow::Result<Migrator> {
116    Ok(
117        migrator!("tool_config" => [ToolConfigV1, ToolConfigV2, ToolConfigV3, ToolConfig], save = true)?,
118    )
119}