relay_knowledge/bootstrap/
cli.rs1use crate::{
8 api::{InterfaceKind, RequestContext},
9 application::KnowledgeMapService,
10 interfaces::cli::{CliAction, CliCommand, OutputFormat},
11 paths::discover_repository_root,
12 project::KNOWLEDGE_MAP_RELATIVE_PATH,
13};
14
15pub use crate::interfaces::cli::{CliError, CliProcessOutput};
16
17pub async fn run_process<I, S>(
24 args: I,
25 interactive_text_output: bool,
26) -> Result<CliProcessOutput, CliError>
27where
28 I: IntoIterator<Item = S>,
29 S: Into<String>,
30{
31 let command = CliCommand::parse(args)?;
32 let stdout = run_command(command, interactive_text_output).await?;
33
34 Ok(CliProcessOutput {
35 stdout,
36 stderr: String::new(),
37 })
38}
39
40pub async fn process_update_notice<I, S>(args: I, interactive_text_output: bool) -> Option<String>
46where
47 I: IntoIterator<Item = S>,
48 S: Into<String>,
49{
50 crate::interfaces::cli::process_update_notice(args, interactive_text_output).await
51}
52
53async fn run_command(
54 command: CliCommand,
55 _interactive_text_output: bool,
56) -> Result<String, CliError> {
57 if let CliAction::Map(map_command) = command.action.clone() {
58 let context = RequestContext::for_interface(InterfaceKind::Cli);
59 let service = if map_command.needs_repository_root() {
60 Some(knowledge_map_service(command.format)?)
61 } else {
62 None
63 };
64 return crate::interfaces::cli::map_cli::run_map(
65 map_command,
66 service.as_ref(),
67 context,
68 command.format,
69 )
70 .await;
71 }
72
73 crate::interfaces::cli::run_command(command).await
74}
75
76fn knowledge_map_service(format: OutputFormat) -> Result<KnowledgeMapService, CliError> {
77 let current = std::env::current_dir().map_err(|error| {
78 CliError::invalid_api_argument(
79 format!("failed to resolve current directory: {error}"),
80 format,
81 )
82 })?;
83 let root = discover_repository_root(¤t)
84 .map_err(|error| CliError::invalid_api_argument(error.to_string(), format))?
85 .ok_or_else(|| {
86 CliError::invalid_api_argument(
87 format!("failed to find repository root for {KNOWLEDGE_MAP_RELATIVE_PATH}"),
88 format,
89 )
90 })?;
91
92 Ok(KnowledgeMapService::new(root))
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[tokio::test]
100 async fn process_entry_delegates_to_existing_cli_behavior() {
101 let bootstrap = run_process(["--version"], false)
102 .await
103 .expect("bootstrap CLI process should render version");
104 let interface = crate::interfaces::cli::run_process(["--version"], false)
105 .await
106 .expect("interface CLI process should render version");
107
108 assert_eq!(bootstrap, interface);
109 }
110}