@@ -9,7 +9,7 @@ mod state;
99use std:: path:: PathBuf ;
1010
1111use anyhow:: { Result , anyhow} ;
12- use clap:: { Parser , Subcommand } ;
12+ use clap:: { Parser , Subcommand , ValueEnum } ;
1313use tracing:: { Event , Subscriber } ;
1414use tracing_subscriber:: EnvFilter ;
1515use tracing_subscriber:: fmt:: FmtContext ;
@@ -47,6 +47,18 @@ enum Command {
4747 #[ arg( long) ]
4848 config : Option < PathBuf > ,
4949 } ,
50+ /// Print built-in reference documentation.
51+ Docs {
52+ #[ arg( value_enum) ]
53+ topic : DocsTopic ,
54+ } ,
55+ }
56+
57+ #[ derive( Debug , Clone , Copy , ValueEnum ) ]
58+ enum DocsTopic {
59+ Config ,
60+ Behavior ,
61+ Security ,
5062}
5163
5264#[ tokio:: main]
@@ -70,6 +82,9 @@ async fn main() -> Result<()> {
7082 config. validate ( ) ?;
7183 Engine :: new ( config) . run ( ) . await ?;
7284 }
85+ Command :: Docs { topic } => {
86+ print ! ( "{}" , docs_text( topic) ) ;
87+ }
7388 }
7489 Ok ( ( ) )
7590}
@@ -128,12 +143,21 @@ fn resolve_config_path(config: Option<PathBuf>) -> Result<PathBuf> {
128143 }
129144}
130145
146+ fn docs_text ( topic : DocsTopic ) -> & ' static str {
147+ match topic {
148+ DocsTopic :: Config => include_str ! ( "../docs/configuration.md" ) ,
149+ DocsTopic :: Behavior => include_str ! ( "../docs/behavior.md" ) ,
150+ DocsTopic :: Security => include_str ! ( "../docs/security.md" ) ,
151+ }
152+ }
153+
131154#[ cfg( test) ]
132155mod tests {
133- use super :: { default_rust_log, format_tracing_prefix} ;
156+ use super :: { Cli , DocsTopic , default_rust_log, docs_text , format_tracing_prefix} ;
134157 use crate :: output:: {
135158 format_output_prefix, normalize_internal_log_label, normalize_source_label,
136159 } ;
160+ use clap:: Parser ;
137161 use std:: sync:: { Mutex , OnceLock } ;
138162
139163 fn rust_log_lock ( ) -> & ' static Mutex < ( ) > {
@@ -198,4 +222,22 @@ mod tests {
198222 assert ! ( rendered. starts_with( "\u{1b} [1;" ) ) ;
199223 assert ! ( rendered. ends_with( " " ) ) ;
200224 }
225+
226+ #[ test]
227+ fn docs_text_uses_embedded_configuration_reference ( ) {
228+ let rendered = docs_text ( DocsTopic :: Config ) ;
229+
230+ assert ! ( rendered. starts_with( "# Configuration Reference" ) ) ;
231+ assert ! ( rendered. contains( "startup_workflows" ) ) ;
232+ }
233+
234+ #[ test]
235+ fn cli_parses_docs_subcommand ( ) {
236+ let cli = Cli :: try_parse_from ( [ "devloop" , "docs" , "security" ] ) . expect ( "parse cli" ) ;
237+
238+ match cli. command {
239+ super :: Command :: Docs { topic } => assert ! ( matches!( topic, DocsTopic :: Security ) ) ,
240+ _ => panic ! ( "expected docs subcommand" ) ,
241+ }
242+ }
201243}
0 commit comments