1mod create;
2mod dep;
3mod doctor;
4mod done;
5mod export;
6mod import;
7mod label;
8mod list;
9mod log;
10mod next;
11mod project;
12mod ready;
13mod reopen;
14mod rm;
15mod search;
16mod show;
17mod skill;
18mod stats;
19pub mod sync;
20mod tidy;
21mod update;
22mod webui;
23
24use crate::cli::{Cli, Command};
25use crate::db;
26use crate::model::{Effort, Priority};
27use anyhow::Result;
28
29fn require_root() -> Result<std::path::PathBuf> {
30 std::env::current_dir().map_err(Into::into)
31}
32
33pub fn dispatch(cli: &Cli) -> Result<()> {
34 if let Some(project) = &cli.project {
35 std::env::set_var(db::PROJECT_ENV, project);
36 }
37
38 match &cli.command {
39 Command::Project { action } => project::run(action, cli.json),
40 Command::Create {
41 title,
42 priority,
43 effort,
44 task_type,
45 desc,
46 parent,
47 labels,
48 } => {
49 let root = require_root()?;
50 create::run(
51 &root,
52 create::Opts {
53 title: title.as_deref(),
54 priority: Priority::parse(priority)?,
55 effort: Effort::parse(effort)?,
56 task_type,
57 desc: desc.as_deref(),
58 parent: parent.as_deref(),
59 labels: labels.as_deref(),
60 json: cli.json,
61 },
62 )
63 }
64 Command::List {
65 status,
66 priority,
67 effort,
68 label,
69 task_type,
70 all,
71 } => {
72 let root = require_root()?;
73 let pri = priority.as_deref().map(Priority::parse).transpose()?;
74 let eff = effort.as_deref().map(Effort::parse).transpose()?;
75 list::run(
76 &root,
77 list::Opts {
78 status: status.as_deref(),
79 priority: pri,
80 effort: eff,
81 label: label.as_deref(),
82 task_type: task_type.as_deref(),
83 all: *all,
84 json: cli.json,
85 },
86 )
87 }
88 Command::Show { id } => {
89 let root = require_root()?;
90 show::run(&root, id, cli.json)
91 }
92 Command::Log { id, message } => {
93 let root = require_root()?;
94 log::run(&root, id, message, cli.json)
95 }
96 Command::Update {
97 id,
98 status,
99 priority,
100 effort,
101 title,
102 desc,
103 task_type,
104 parent,
105 } => {
106 let root = require_root()?;
107 let pri = priority.as_deref().map(Priority::parse).transpose()?;
108 let eff = effort.as_deref().map(Effort::parse).transpose()?;
109 // --parent "" means clear; --parent <id> means set; absent means don't change.
110 let parent_opt =
111 parent
112 .as_ref()
113 .map(|p| if p.is_empty() { None } else { Some(p.as_str()) });
114 update::run(
115 &root,
116 id,
117 update::Opts {
118 status: status.as_deref(),
119 priority: pri,
120 effort: eff,
121 title: title.as_deref(),
122 desc: desc.as_deref(),
123 task_type: task_type.as_deref(),
124 parent: parent_opt,
125 json: cli.json,
126 },
127 )
128 }
129 Command::Done { ids } => {
130 let root = require_root()?;
131 done::run(&root, ids, cli.json)
132 }
133 Command::Rm {
134 force,
135 recursive,
136 ids,
137 } => {
138 let root = require_root()?;
139 rm::run(&root, ids, *recursive, *force, cli.json)
140 }
141 Command::Reopen { ids } => {
142 let root = require_root()?;
143 reopen::run(&root, ids, cli.json)
144 }
145 Command::Dep { action } => {
146 let root = require_root()?;
147 dep::run(&root, action, cli.json)
148 }
149 Command::Label { action } => {
150 let root = require_root()?;
151 label::run(&root, action, cli.json)
152 }
153 Command::Search { query } => {
154 let root = require_root()?;
155 search::run(&root, query, cli.json)
156 }
157 Command::Ready => {
158 let root = require_root()?;
159 ready::run(&root, cli.json)
160 }
161 Command::Next {
162 mode,
163 verbose,
164 limit,
165 } => {
166 let root = require_root()?;
167 next::run(&root, mode, *verbose, *limit, cli.json)
168 }
169 Command::Stats => {
170 let root = require_root()?;
171 stats::run(&root)
172 }
173 Command::Doctor { fix } => {
174 let root = require_root()?;
175 doctor::run(&root, *fix, cli.json)
176 }
177 Command::Tidy => {
178 let root = require_root()?;
179 tidy::run(&root)
180 }
181 Command::Export => {
182 let root = require_root()?;
183 export::run(&root)
184 }
185 Command::Import { file } => {
186 let root = require_root()?;
187 import::run(&root, file)
188 }
189 Command::Sync { code } => {
190 let root = require_root()?;
191 sync::run(&root, code.as_deref(), cli.json)
192 }
193 Command::WebUi { host, port } => {
194 let root = require_root()?;
195 webui::run(&root, host, *port, cli.project.as_deref())
196 }
197 Command::Skill { dir } => skill::run(dir.as_deref()),
198 }
199}