Skip to main content

lean_ctx/core/gain/
task_classifier.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
4pub enum TaskCategory {
5    Coding,
6    Debugging,
7    Refactoring,
8    Testing,
9    Exploration,
10    Planning,
11    Delegation,
12    Git,
13    BuildDeploy,
14    Knowledge,
15    Architecture,
16    Review,
17    General,
18}
19
20impl TaskCategory {
21    pub fn label(&self) -> &'static str {
22        match self {
23            TaskCategory::Coding => "Coding",
24            TaskCategory::Debugging => "Debugging",
25            TaskCategory::Refactoring => "Refactoring",
26            TaskCategory::Testing => "Testing",
27            TaskCategory::Exploration => "Exploration",
28            TaskCategory::Planning => "Planning",
29            TaskCategory::Delegation => "Delegation",
30            TaskCategory::Git => "Git",
31            TaskCategory::BuildDeploy => "Build/Deploy",
32            TaskCategory::Knowledge => "Knowledge",
33            TaskCategory::Architecture => "Architecture",
34            TaskCategory::Review => "Review",
35            TaskCategory::General => "General",
36        }
37    }
38}
39
40pub struct TaskClassifier;
41
42impl TaskClassifier {
43    pub fn classify_tool(tool_name: &str) -> TaskCategory {
44        let t = normalize(tool_name);
45        match t.as_str() {
46            "ctx_edit" | "ctx_fill" => TaskCategory::Refactoring,
47            "ctx_read" | "ctx_multi_read" | "ctx_smart_read" | "ctx_delta" => {
48                TaskCategory::Exploration
49            }
50            "ctx_tree" | "ctx_search" | "ctx_outline" | "ctx_graph" | "ctx_graph_diagram" => {
51                TaskCategory::Exploration
52            }
53            "ctx_semantic_search" | "ctx_architecture" | "ctx_impact" => TaskCategory::Architecture,
54            "ctx_overview" | "ctx_preload" | "ctx_task" | "ctx_intent" | "ctx_workflow" => {
55                TaskCategory::Planning
56            }
57            "ctx_handoff" | "ctx_agent" | "ctx_share" => TaskCategory::Delegation,
58            "ctx_session" | "ctx_knowledge" | "ctx_compress_memory" => TaskCategory::Knowledge,
59            "ctx_cost" | "ctx_gain" | "ctx_metrics" | "ctx_wrapped" | "ctx_heatmap" => {
60                TaskCategory::Review
61            }
62            "ctx_shell" | "ctx_execute" => TaskCategory::Debugging,
63            _ => TaskCategory::General,
64        }
65    }
66
67    pub fn classify_command_key(cmd_key: &str) -> TaskCategory {
68        let k = normalize(cmd_key);
69        if k.is_empty() {
70            return TaskCategory::General;
71        }
72        if k.starts_with("git ") || k == "git" {
73            return TaskCategory::Git;
74        }
75
76        if k.starts_with("cargo ") {
77            let sub = k.trim_start_matches("cargo ").trim();
78            if matches!(sub, "test" | "nextest" | "llvm-cov" | "tarpaulin") {
79                return TaskCategory::Testing;
80            }
81            if matches!(sub, "build" | "check" | "clippy" | "fmt" | "run" | "doc") {
82                return TaskCategory::BuildDeploy;
83            }
84            return TaskCategory::BuildDeploy;
85        }
86
87        if k.contains("test") || k.contains("pytest") || k.contains("jest") || k.contains("vitest")
88        {
89            return TaskCategory::Testing;
90        }
91        if k.contains("build")
92            || k.contains("deploy")
93            || k.contains("docker")
94            || k.contains("compose")
95            || k.contains("kubectl")
96            || k.contains("helm")
97            || k.contains("terraform")
98        {
99            return TaskCategory::BuildDeploy;
100        }
101        if k.contains("lint") || k.contains("clippy") || k.contains("fmt") || k.contains("format") {
102            return TaskCategory::BuildDeploy;
103        }
104        if k.contains("grep") || k.contains("rg") || k.contains("ripgrep") {
105            return TaskCategory::Exploration;
106        }
107
108        TaskCategory::General
109    }
110}
111
112fn normalize(s: &str) -> String {
113    s.trim().to_lowercase()
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn classify_git() {
122        assert_eq!(
123            TaskClassifier::classify_command_key("git status"),
124            TaskCategory::Git
125        );
126    }
127
128    #[test]
129    fn classify_tools() {
130        assert_eq!(
131            TaskClassifier::classify_tool("ctx_semantic_search"),
132            TaskCategory::Architecture
133        );
134    }
135}