Skip to main content

dsp_cli/
lib.rs

1//! `dsp-cli` — AI-agent-friendly CLI for the DaSCH Service Platform.
2//!
3//! The orientation entry point is `idea.md` in the repository root; the
4//! ubiquitous-language reference is `CONTEXT.md`. The internal architecture
5//! is described in ADR-0008 (`docs/adr/0008-internal-architecture.md`).
6//!
7//! This crate exposes a library surface so tests can reach the action layer
8//! without going through the binary; the binary itself is `src/main.rs`.
9
10pub mod actions;
11pub mod cli;
12pub mod client;
13pub mod config;
14pub mod diagnostic;
15pub mod model;
16pub mod render;
17pub mod update;
18pub(crate) mod util;
19
20use crate::cli::{
21    AuthCmd, Cli, DataModelCmd, ProjectCmd, ResourceCmd, ResourceTypeCmd, SparqlCmd, TopLevel,
22    VocabularyCmd, VreCmd,
23};
24use crate::client::http::HttpDspClient;
25use crate::config::Config;
26use crate::diagnostic::Diagnostic;
27
28/// Top-level entry point used by `main.rs` and by integration tests.
29///
30/// Routes CLI commands to the appropriate action function. The match is
31/// exhaustive — adding a new variant forces an explicit dispatch update.
32///
33/// For vre leaf commands and auth commands, the renderer is constructed from
34/// the `--format` / `-j` / `-l` flags parsed into `FormatArgs` and resolved
35/// via `FormatArgs::resolve().into_renderer()`. The auth commands additionally
36/// build a `Config` from `--server`/`DSP_SERVER` and, for login, an
37/// `HttpDspClient`.
38pub fn run(cli: Cli) -> Result<(), Diagnostic> {
39    match cli.command {
40        TopLevel::Auth { cmd } => match cmd {
41            AuthCmd::Login(args) => {
42                let cfg = Config::resolve(args.server.as_deref())?;
43                let client = HttpDspClient::new()?;
44                let fmt = args.format.resolve();
45                let opts = args.format.table_options(fmt)?;
46                let mut renderer = fmt.into_renderer_with_options(opts);
47                actions::auth::login::run(&args, &cfg, &client, &mut *renderer)
48            }
49            AuthCmd::Status(args) => {
50                let cfg = Config::resolve(args.server.as_deref())?;
51                let fmt = args.format.resolve();
52                let opts = args.format.table_options(fmt)?;
53                let mut renderer = fmt.into_renderer_with_options(opts);
54                actions::auth::status::run(&args, &cfg, &mut *renderer)
55            }
56            AuthCmd::Logout(args) => {
57                let cfg = Config::resolve(args.server.as_deref())?;
58                let fmt = args.format.resolve();
59                let opts = args.format.table_options(fmt)?;
60                let mut renderer = fmt.into_renderer_with_options(opts);
61                actions::auth::logout::run(&args, &cfg, &mut *renderer)
62            }
63            AuthCmd::SetToken(args) => {
64                let cfg = Config::resolve(args.server.as_deref())?;
65                let client = HttpDspClient::new()?;
66                let fmt = args.format.resolve();
67                let opts = args.format.table_options(fmt)?;
68                let mut renderer = fmt.into_renderer_with_options(opts);
69                actions::auth::set_token::run(&cfg, &client, &mut *renderer)
70            }
71            AuthCmd::Token(args) => {
72                let cfg = Config::resolve(args.server.as_deref())?;
73                actions::auth::token::run(&cfg)
74            }
75        },
76
77        TopLevel::Vre { cmd } => match cmd {
78            VreCmd::Project { cmd } => match cmd {
79                ProjectCmd::List(args) => {
80                    let cfg = Config::resolve(args.server.as_deref())?;
81                    let client = HttpDspClient::new()?;
82                    let fmt = args.format.resolve();
83                    let opts = args.format.table_options(fmt)?;
84                    let mut renderer = fmt.into_renderer_with_options(opts);
85                    actions::vre::project::list(&args, &cfg, &client, &mut *renderer)
86                }
87                ProjectCmd::Describe(args) => {
88                    let cfg = Config::resolve(args.server.as_deref())?;
89                    let client = HttpDspClient::new()?;
90                    let fmt = args.format.resolve();
91                    let opts = args.format.table_options(fmt)?;
92                    let mut renderer = fmt.into_renderer_with_options(opts);
93                    actions::vre::project::describe(&args, &cfg, &client, &mut *renderer)
94                }
95                ProjectCmd::Dump(args) => {
96                    let cfg = Config::resolve(args.server.as_deref())?;
97                    let client = HttpDspClient::new()?;
98                    let fmt = args.format.resolve();
99                    let opts = args.format.table_options(fmt)?;
100                    let mut renderer = fmt.into_renderer_with_options(opts);
101                    let mut reporter = fmt.into_progress_reporter();
102                    actions::vre::project::dump(
103                        &args,
104                        &cfg,
105                        &client,
106                        &mut *renderer,
107                        &mut *reporter,
108                    )
109                }
110            },
111            VreCmd::DataModel { cmd } => match cmd {
112                DataModelCmd::List(args) => {
113                    let cfg = Config::resolve(args.server.as_deref())?;
114                    let client = HttpDspClient::new()?;
115                    let fmt = args.format.resolve();
116                    let opts = args.format.table_options(fmt)?;
117                    let mut renderer = fmt.into_renderer_with_options(opts);
118                    actions::vre::data_model::list(&args, &cfg, &client, &mut *renderer)
119                }
120                DataModelCmd::Describe(args) => {
121                    let cfg = Config::resolve(args.server.as_deref())?;
122                    let client = HttpDspClient::new()?;
123                    let fmt = args.format.resolve();
124                    let opts = args.format.table_options(fmt)?;
125                    let mut renderer = fmt.into_renderer_with_options(opts);
126                    actions::vre::data_model::describe(&args, &cfg, &client, &mut *renderer)
127                }
128                DataModelCmd::Structure(args) => {
129                    let cfg = Config::resolve(args.server.as_deref())?;
130                    let client = HttpDspClient::new()?;
131                    let fmt = args.format.resolve();
132                    let opts = args.format.table_options(fmt)?;
133                    let mut renderer = fmt.into_renderer_with_options(opts);
134                    actions::vre::data_model::structure(&args, &cfg, &client, &mut *renderer)
135                }
136            },
137            VreCmd::ResourceType { cmd } => match cmd {
138                ResourceTypeCmd::List(args) => {
139                    let cfg = Config::resolve(args.server.as_deref())?;
140                    let client = HttpDspClient::new()?;
141                    let fmt = args.format.resolve();
142                    let opts = args.format.table_options(fmt)?;
143                    let mut renderer = fmt.into_renderer_with_options(opts);
144                    actions::vre::resource_type::list(&args, &cfg, &client, &mut *renderer)
145                }
146                ResourceTypeCmd::Describe(args) => {
147                    let cfg = Config::resolve(args.server.as_deref())?;
148                    let client = HttpDspClient::new()?;
149                    let fmt = args.format.resolve();
150                    let opts = args.format.table_options(fmt)?;
151                    let mut renderer = fmt.into_renderer_with_options(opts);
152                    actions::vre::resource_type::describe(&args, &cfg, &client, &mut *renderer)
153                }
154            },
155            VreCmd::Resource { cmd } => match cmd {
156                ResourceCmd::List(args) => {
157                    let cfg = Config::resolve(args.server.as_deref())?;
158                    let client = HttpDspClient::new()?;
159                    let fmt = args.format.resolve();
160                    let opts = args.format.table_options(fmt)?;
161                    let mut renderer = fmt.into_renderer_with_options(opts);
162                    actions::vre::resource::list(&args, &cfg, &client, &mut *renderer)
163                }
164                ResourceCmd::Describe(args) => {
165                    let cfg = Config::resolve(args.server.as_deref())?;
166                    let client = HttpDspClient::new()?;
167                    let fmt = args.format.resolve();
168                    let opts = args.format.table_options(fmt)?;
169                    let mut renderer = fmt.into_renderer_with_options(opts);
170                    actions::vre::resource::describe(&args, &cfg, &client, &mut *renderer)
171                }
172            },
173            VreCmd::Vocabulary { cmd } => match cmd {
174                VocabularyCmd::List(args) => {
175                    let cfg = Config::resolve(args.server.as_deref())?;
176                    let client = HttpDspClient::new()?;
177                    let fmt = args.format.resolve();
178                    let opts = args.format.table_options(fmt)?;
179                    let mut renderer = fmt.into_renderer_with_options(opts);
180                    actions::vre::vocabulary::list(&args, &cfg, &client, &mut *renderer)
181                }
182                VocabularyCmd::Describe(args) => {
183                    let cfg = Config::resolve(args.server.as_deref())?;
184                    let client = HttpDspClient::new()?;
185                    let fmt = args.format.resolve();
186                    let opts = args.format.table_options(fmt)?;
187                    let mut renderer = fmt.into_renderer_with_options(opts);
188                    actions::vre::vocabulary::describe(&args, &cfg, &client, &mut *renderer)
189                }
190            },
191            // No renderer, no table_options — D2/D16: the response is a
192            // store-authored byte stream, not a dsp-cli-rendered view.
193            VreCmd::Sparql { cmd } => match cmd {
194                SparqlCmd::Query(args) => {
195                    let cfg = Config::resolve(args.server.as_deref())?;
196                    let client = HttpDspClient::new()?;
197                    actions::vre::sparql::run(&args, &cfg, &client)
198                }
199            },
200        },
201
202        TopLevel::Docs(args) => actions::docs::run(&args),
203    }
204}