Skip to main content

vtcode_core/cli/
man_pages.rs

1//! Man page generation for VT Code CLI using roff-rs
2//!
3//! This module provides functionality to generate Unix man pages for VT Code
4//! commands and subcommands using the roff-rs library.
5
6use anyhow::{Context, Result, bail};
7use roff::{Roff, bold, italic, roman};
8use std::path::Path;
9use tokio::fs;
10
11/// Man page generator for VT Code CLI
12pub struct ManPageGenerator;
13
14impl ManPageGenerator {
15    /// Get current date in YYYY-MM-DD format
16    fn current_date() -> String {
17        use chrono::Utc;
18        Utc::now().format("%Y-%m-%d").to_string()
19    }
20
21    /// Generate man page for the main VT Code command
22    pub fn generate_main_man_page() -> Result<String> {
23        let current_date = Self::current_date();
24        let page = Roff::new()
25            .control("TH", ["VTCODE", "1", &current_date, "VT Code", "User Commands"])
26            .control("SH", ["NAME"])
27            .text([roman("vtcode - Advanced coding agent with Decision Ledger")])
28            .control("SH", ["SYNOPSIS"])
29            .text([
30                bold("vtcode"),
31                roman(" ["),
32                bold("OPTIONS"),
33                roman("] ["),
34                bold("COMMAND"),
35                roman("] ["),
36                bold("ARGS"),
37                roman("]"),
38            ])
39            .control("SH", ["DESCRIPTION"])
40            .text([
41                roman("VT Code is an advanced coding agent with single-agent architecture and Decision Ledger that provides"),
42                roman(" intelligent code generation, analysis, and modification capabilities. It supports"),
43                roman(" multiple LLM providers including Gemini, OpenAI, Anthropic, DeepSeek, Z.AI,"),
44                roman(" Moonshot AI, OpenRouter, and Ollama, and includes LLM-native semantic code understanding."),
45                roman(" Rust, Python, JavaScript, TypeScript, Go, and Java."),
46            ])
47            .control("SH", ["OPTIONS"])
48            .control("TP", [])
49            .text([bold("-m"), roman(", "), bold("--model"), roman(" "), italic("MODEL")])
50            .text([roman("Specify the LLM model to use (default: gemini-3-flash-preview)")])
51            .control("TP", [])
52            .text([bold("-p"), roman(", "), bold("--provider"), roman(" "), italic("PROVIDER")])
53            .text([
54                roman(
55                    "Specify the LLM provider (gemini, openai, anthropic, deepseek, zai, moonshot, openrouter, ollama, lmstudio)",
56                ),
57            ])
58            .control("TP", [])
59            .text([bold("--workspace"), roman(" "), italic("PATH")])
60            .text([roman("Set the workspace root directory for file operations")])
61            .control("TP", [])
62            .text([bold("--performance-monitoring")])
63            .text([roman("Enable performance monitoring and metrics")])
64            .control("TP", [])
65            .text([bold("--research-preview")])
66            .text([roman("Enable research-preview features")])
67            .control("TP", [])
68            .text([bold("--debug")])
69            .text([roman("Enable debug output")])
70            .control("TP", [])
71            .text([bold("--verbose")])
72            .text([roman("Enable verbose logging")])
73            .control("TP", [])
74            .text([bold("-h"), roman(", "), bold("--help")])
75            .text([roman("Display help information")])
76            .control("TP", [])
77            .text([bold("-V"), roman(", "), bold("--version")])
78            .text([roman("Display version information")])
79            .control("SH", ["COMMANDS"])
80            .control("TP", [])
81            .text([bold("chat")])
82            .text([roman("Start interactive AI coding assistant")])
83            .control("TP", [])
84            .text([bold("ask"), roman(" "), italic("PROMPT")])
85            .text([roman("Single prompt mode without tools")])
86            .control("TP", [])
87            .text([bold("performance")])
88            .text([roman("Display performance metrics and system status")])
89            .control("TP", [])
90            .text([bold("benchmark")])
91            .text([roman("Run SWE-bench evaluation framework")])
92            .control("TP", [])
93            .text([bold("create-project"), roman(" "), italic("NAME"), roman(" "), italic("FEATURES")])
94            .text([roman("Create complete Rust project with features")])
95            .control("TP", [])
96            .text([bold("init")])
97            .text([roman("Guided AGENTS.md and workspace setup")])
98            .control("TP", [])
99            .text([bold("man"), roman(" "), italic("COMMAND")])
100            .text([roman("Generate or display man pages for commands")])
101            .control("TP", [])
102            .text([bold("check"), roman(" "), italic("SUBCOMMAND")])
103            .text([roman("Run built-in repository checks")])
104            .control("TP", [])
105            .text([bold("acp")])
106            .text([roman("Start Agent Client Protocol bridge for IDE integrations")])
107            .control("TP", [])
108            .text([bold("chat-verbose")])
109            .text([roman("Verbose interactive chat with enhanced transparency")])
110            .control("TP", [])
111            .text([bold("performance")])
112            .text([roman("Display performance metrics and system status")])
113            .control("TP", [])
114            .text([bold("trajectory")])
115            .text([roman("Pretty-print trajectory logs and show basic analytics")])
116            .control("TP", [])
117            .text([bold("benchmark")])
118            .text([roman("Benchmark against SWE-bench evaluation framework")])
119            .control("TP", [])
120            .text([bold("create-project"), roman(" "), italic("name"), roman(" "), italic("features")])
121            .text([roman("Create complete Rust project with advanced features")])
122            .control("TP", [])
123
124            .control("TP", [])
125            .text([bold("revert"), roman(" "), italic("turn")])
126            .text([roman("Revert agent to a previous snapshot")])
127            .control("TP", [])
128            .text([bold("snapshots")])
129            .text([roman("List all available snapshots")])
130            .control("TP", [])
131            .text([bold("cleanup-snapshots")])
132            .text([roman("Clean up old snapshots")])
133            .control("TP", [])
134            .text([bold("init")])
135            .text([roman("Initialize project with enhanced dot-folder structure")])
136            .control("TP", [])
137            .text([bold("init-project")])
138            .text([roman("Initialize project with dot-folder structure")])
139            .control("TP", [])
140            .text([bold("config")])
141            .text([roman("Generate configuration file")])
142            .control("TP", [])
143            .text([bold("tool-policy")])
144            .text([roman("Manage tool execution policies")])
145            .control("TP", [])
146            .text([bold("mcp")])
147            .text([roman("Manage Model Context Protocol providers")])
148            .control("TP", [])
149            .text([bold("models")])
150            .text([roman("Manage models and providers")])
151            .control("SH", ["EXAMPLES"])
152            .text([roman("Start interactive chat:")])
153            .text([bold("  vtcode chat")])
154            .text([roman("Ask a question:")])
155            .text([bold("  vtcode ask \"Explain Rust ownership\"")])
156            .text([roman("Create a web project:")])
157            .text([bold("  vtcode create-project myapp web,auth,db")])
158            .text([roman("Generate man page:")])
159            .text([bold("  vtcode man chat")])
160            .text([roman("Run ast-grep checks for the current workspace:")])
161            .text([bold("  vtcode check ast-grep")])
162            .control("SH", ["ENVIRONMENT"])
163            .control("TP", [])
164            .text([bold("GEMINI_API_KEY")])
165            .text([roman("API key for Google Gemini (default provider)")])
166            .control("TP", [])
167            .text([bold("OPENAI_API_KEY")])
168            .text([roman("API key for OpenAI GPT models")])
169            .control("TP", [])
170            .text([bold("ANTHROPIC_API_KEY")])
171            .text([roman("API key for Anthropic Claude models")])
172            .control("TP", [])
173            .text([bold("DEEPSEEK_API_KEY")])
174            .text([roman("API key for DeepSeek models")])
175            .control("TP", [])
176            .text([bold("ZAI_API_KEY")])
177            .text([roman("API key for Z.AI GLM models")])
178            .control("TP", [])
179            .text([bold("MOONSHOT_API_KEY")])
180            .text([roman("API key for Moonshot AI Kimi models")])
181            .control("TP", [])
182            .text([bold("OPENROUTER_API_KEY")])
183            .text([roman("API key for OpenRouter models")])
184            .control("SH", ["FILES"])
185            .control("TP", [])
186            .text([bold("vtcode.toml")])
187            .text([roman("Configuration file (current directory or ~/.vtcode/)")])
188            .control("TP", [])
189            .text([bold(".vtcode/")])
190            .text([roman("Project cache and context directory")])
191            .control("SH", ["SAFETY"])
192            .control("TP", [])
193            .text([roman(
194                "apply_patch: reserve for reviewed diffs or small batches. For large refactors or critical files, stage local backups and prefer edit_file/write_file to avoid partial rewrites if a patch fails.",
195            )])
196            .control("TP", [])
197            .text([roman(
198                "Timeout governance: tune [timeouts] in vtcode.toml to clamp tool duration. VT Code warns once execution passes the configured warning threshold so you can cancel runaway commands.",
199            )])
200            .control("SH", ["SEE ALSO"])
201            .text([roman("Full documentation: https://github.com/vinhnx/vtcode")])
202            .text([roman("Related commands: cargo(1), rustc(1), git(1)")])
203            .render();
204
205        Ok(page)
206    }
207
208    /// Generate man page for a specific command
209    pub fn generate_command_man_page(command: &str) -> Result<String> {
210        match command {
211            "chat" => Self::generate_chat_man_page(),
212            "ask" => Self::generate_ask_man_page(),
213            "performance" => Self::generate_performance_man_page(),
214            "benchmark" => Self::generate_benchmark_man_page(),
215            "check" => Self::generate_check_man_page(),
216            "create-project" => Self::generate_create_project_man_page(),
217            "init" => Self::generate_init_man_page(),
218            "man" => Self::generate_man_man_page(),
219            _ => bail!("Unknown command: {}", command),
220        }
221    }
222
223    /// Generate man page for the chat command
224    fn generate_chat_man_page() -> Result<String> {
225        let current_date = Self::current_date();
226        let page = Roff::new()
227            .control("TH", ["VTCODE-CHAT", "1", &current_date, "VT Code", "User Commands"])
228            .control("SH", ["NAME"])
229            .text([roman("vtcode-chat - Interactive AI coding assistant")])
230            .control("SH", ["SYNOPSIS"])
231            .text([
232                bold("vtcode"),
233                roman(" ["),
234                bold("OPTIONS"),
235                roman("] "),
236                bold("chat"),
237            ])
238            .control("SH", ["DESCRIPTION"])
239            .text([
240                roman("Start an interactive AI coding assistant session."),
241                roman(" The chat command provides intelligent code generation, analysis, and modification"),
242                roman(" with support for multiple LLM providers and semantic code analysis."),
243            ])
244            .control("SH", ["OPTIONS"])
245            .text([roman("All global options are supported. See "), bold("vtcode(1)"), roman(" for details.")])
246            .control("SH", ["EXAMPLES"])
247            .text([roman("Start basic chat session:")])
248            .text([bold("  vtcode chat")])
249            .text([roman("Start with specific model:")])
250            .text([bold("  vtcode --model gemini-3.1-pro-preview chat")])
251            .control("SH", ["SEE ALSO"])
252            .text([bold("vtcode(1)"), roman(", "), bold("vtcode-ask(1)"), roman(", "), bold("vtcode-analyze(1)")])
253            .render();
254
255        Ok(page)
256    }
257
258    /// Generate man page for the ask command
259    fn generate_ask_man_page() -> Result<String> {
260        let current_date = Self::current_date();
261        let page = Roff::new()
262            .control("TH", ["VTCODE-ASK", "1", &current_date, "VT Code", "User Commands"])
263            .control("SH", ["NAME"])
264            .text([roman("vtcode-ask - Single prompt mode without tools")])
265            .control("SH", ["SYNOPSIS"])
266            .text([
267                bold("vtcode"),
268                roman(" ["),
269                bold("OPTIONS"),
270                roman("] "),
271                bold("ask"),
272                roman(" "),
273                italic("PROMPT"),
274            ])
275            .control("SH", ["DESCRIPTION"])
276            .text([
277                roman("Execute a single prompt without tool usage. This is perfect for quick questions,"),
278                roman(" code explanations, and simple queries that don't require file operations or"),
279                roman(" complex tool interactions."),
280            ])
281            .control("SH", ["EXAMPLES"])
282            .text([roman("Ask about Rust ownership:")])
283            .text([bold("  vtcode ask \"Explain Rust ownership\"")])
284            .text([roman("Get code explanation:")])
285            .text([bold("  vtcode ask \"What does this regex do: \\w+@\\w+\\.\\w+\"")])
286            .control("SH", ["SEE ALSO"])
287            .text([bold("vtcode(1)"), roman(", "), bold("vtcode-chat(1)")])
288            .render();
289
290        Ok(page)
291    }
292
293    /// Generate man page for the analyze command
294    /// Generate man page for the performance command
295    fn generate_performance_man_page() -> Result<String> {
296        let current_date = Self::current_date();
297        let page = Roff::new()
298            .control(
299                "TH",
300                [
301                    "VTCODE-PERFORMANCE",
302                    "1",
303                    &current_date,
304                    "VT Code",
305                    "User Commands",
306                ],
307            )
308            .control("SH", ["NAME"])
309            .text([roman(
310                "vtcode-performance - Display performance metrics and system status",
311            )])
312            .control("SH", ["SYNOPSIS"])
313            .text([
314                bold("vtcode"),
315                roman(" ["),
316                bold("OPTIONS"),
317                roman("] "),
318                bold("performance"),
319            ])
320            .control("SH", ["DESCRIPTION"])
321            .text([
322                roman("Display comprehensive performance metrics and system status information."),
323                roman(" Shows token usage, API costs, response times, tool execution statistics,"),
324                roman(" memory usage patterns, and agent performance metrics."),
325            ])
326            .control("SH", ["METRICS DISPLAYED"])
327            .control("TP", [])
328            .text([bold("Token Usage")])
329            .text([roman("Input/output token counts and API costs")])
330            .control("TP", [])
331            .text([bold("Response Times")])
332            .text([roman("API response latency and processing times")])
333            .control("TP", [])
334            .text([bold("Tool Execution")])
335            .text([roman("Tool call statistics and execution times")])
336            .control("TP", [])
337            .text([bold("Memory Usage")])
338            .text([roman("Memory consumption patterns")])
339            .control("TP", [])
340            .text([bold("Agent Performance")])
341            .text([roman("Single-agent execution metrics")])
342            .control("SH", ["EXAMPLES"])
343            .text([roman("Show performance metrics:")])
344            .text([bold("  vtcode performance")])
345            .control("SH", ["SEE ALSO"])
346            .text([bold("vtcode(1)"), roman(", "), bold("vtcode-benchmark(1)")])
347            .render();
348
349        Ok(page)
350    }
351
352    /// Generate man page for the benchmark command
353    fn generate_benchmark_man_page() -> Result<String> {
354        let current_date = Self::current_date();
355        let page = Roff::new()
356            .control(
357                "TH",
358                [
359                    "VTCODE-BENCHMARK",
360                    "1",
361                    &current_date,
362                    "VT Code",
363                    "User Commands",
364                ],
365            )
366            .control("SH", ["NAME"])
367            .text([roman(
368                "vtcode-benchmark - Run SWE-bench evaluation framework",
369            )])
370            .control("SH", ["SYNOPSIS"])
371            .text([
372                bold("vtcode"),
373                roman(" ["),
374                bold("OPTIONS"),
375                roman("] "),
376                bold("benchmark"),
377            ])
378            .control("SH", ["DESCRIPTION"])
379            .text([
380                roman(
381                    "Run automated performance testing against the SWE-bench evaluation framework.",
382                ),
383                roman(" Provides comparative analysis across different models, benchmark scoring,"),
384                roman(" and optimization insights for coding tasks."),
385            ])
386            .control("SH", ["FEATURES"])
387            .control("TP", [])
388            .text([bold("Automated Testing")])
389            .text([roman("Run standardized coding tasks and challenges")])
390            .control("TP", [])
391            .text([bold("Comparative Analysis")])
392            .text([roman("Compare performance across different models")])
393            .control("TP", [])
394            .text([bold("Benchmark Scoring")])
395            .text([roman("Quantitative performance metrics and scores")])
396            .control("TP", [])
397            .text([bold("Optimization Insights")])
398            .text([roman("Recommendations for performance improvements")])
399            .control("SH", ["EXAMPLES"])
400            .text([roman("Run benchmark suite:")])
401            .text([bold("  vtcode benchmark")])
402            .control("SH", ["SEE ALSO"])
403            .text([
404                bold("vtcode(1)"),
405                roman(", "),
406                bold("vtcode-performance(1)"),
407            ])
408            .render();
409
410        Ok(page)
411    }
412
413    /// Generate man page for the create-project command
414    fn generate_create_project_man_page() -> Result<String> {
415        let current_date = Self::current_date();
416        let page = Roff::new()
417            .control(
418                "TH",
419                [
420                    "VTCODE-CREATE-PROJECT",
421                    "1",
422                    &current_date,
423                    "VT Code",
424                    "User Commands",
425                ],
426            )
427            .control("SH", ["NAME"])
428            .text([roman(
429                "vtcode-create-project - Create complete Rust project with features",
430            )])
431            .control("SH", ["SYNOPSIS"])
432            .text([
433                bold("vtcode"),
434                roman(" ["),
435                bold("OPTIONS"),
436                roman("] "),
437                bold("create-project"),
438                roman(" "),
439                italic("NAME"),
440                roman(" "),
441                italic("FEATURES"),
442            ])
443            .control("SH", ["DESCRIPTION"])
444            .text([
445                roman("Create a complete Rust project with advanced features and integrations."),
446                roman(" Supports web frameworks, database integration, authentication systems,"),
447                roman(" testing setup, and security policies."),
448            ])
449            .control("SH", ["AVAILABLE FEATURES"])
450            .text([roman("• web - Web framework (Axum, Rocket, Warp)")])
451            .text([roman("• auth - Authentication system")])
452            .text([roman("• db - Database integration")])
453            .text([roman("• test - Testing setup")])
454            .control("SH", ["EXAMPLES"])
455            .text([roman("Create web app with auth and database:")])
456            .text([bold("  vtcode create-project myapp web,auth,db")])
457            .text([roman("Create basic project:")])
458            .text([bold("  vtcode create-project simple_app")])
459            .control("SH", ["SEE ALSO"])
460            .text([bold("vtcode(1)"), roman(", "), bold("vtcode-init(1)")])
461            .render();
462
463        Ok(page)
464    }
465
466    /// Generate man page for the init command
467    fn generate_init_man_page() -> Result<String> {
468        let current_date = Self::current_date();
469        let page = Roff::new()
470            .control(
471                "TH",
472                [
473                    "VTCODE-INIT",
474                    "1",
475                    &current_date,
476                    "VT Code",
477                    "User Commands",
478                ],
479            )
480            .control("SH", ["NAME"])
481            .text([roman("vtcode-init - Guided AGENTS.md and workspace setup")])
482            .control("SH", ["SYNOPSIS"])
483            .text([
484                bold("vtcode"),
485                roman(" ["),
486                bold("OPTIONS"),
487                roman("] "),
488                bold("init"),
489                roman(" ["),
490                bold("--force"),
491                roman("]"),
492            ])
493            .control("SH", ["DESCRIPTION"])
494            .text([
495                roman("Bootstrap vtcode.toml, repository memory scaffolding, indexing,"),
496                roman(" and a guided root AGENTS.md generated from repository signals."),
497                roman(" Existing AGENTS.md files prompt for confirmation unless --force is used."),
498            ])
499            .control("SH", ["EXAMPLES"])
500            .text([roman("Initialize current directory:")])
501            .text([bold("  vtcode init")])
502            .text([roman("Overwrite an existing AGENTS.md without prompting:")])
503            .text([bold("  vtcode init --force")])
504            .control("SH", ["SEE ALSO"])
505            .text([
506                bold("vtcode(1)"),
507                roman(", "),
508                bold("vtcode-create-project(1)"),
509            ])
510            .render();
511
512        Ok(page)
513    }
514
515    /// Generate man page for the check command
516    fn generate_check_man_page() -> Result<String> {
517        let current_date = Self::current_date();
518        let page = Roff::new()
519            .control(
520                "TH",
521                [
522                    "VTCODE-CHECK",
523                    "1",
524                    &current_date,
525                    "VT Code",
526                    "User Commands",
527                ],
528            )
529            .control("SH", ["NAME"])
530            .text([roman("vtcode-check - Run built-in repository checks")])
531            .control("SH", ["SYNOPSIS"])
532            .text([
533                bold("vtcode"),
534                roman(" ["),
535                bold("OPTIONS"),
536                roman("] "),
537                bold("check"),
538                roman(" "),
539                bold("ast-grep"),
540            ])
541            .control("SH", ["DESCRIPTION"])
542            .text([
543                roman("Run built-in checks against the current workspace. The "),
544                bold("ast-grep"),
545                roman(" subcommand runs "),
546                bold("ast-grep test --config sgconfig.yml"),
547                roman(" followed by "),
548                bold("ast-grep scan --config sgconfig.yml"),
549                roman("."),
550            ])
551            .control("SH", ["PREREQUISITES"])
552            .text([roman("Install ast-grep with:")])
553            .text([bold("  vtcode dependencies install ast-grep")])
554            .text([roman("Materialize the local scaffold with:")])
555            .text([bold("  vtcode init")])
556            .control("SH", ["EXAMPLES"])
557            .text([roman("Run ast-grep rule tests and scan:")])
558            .text([bold("  vtcode check ast-grep")])
559            .control("SH", ["SEE ALSO"])
560            .text([
561                bold("vtcode(1)"),
562                roman(", "),
563                bold("vtcode-init(1)"),
564                roman(", "),
565                bold("vtcode-man(1)"),
566            ])
567            .render();
568
569        Ok(page)
570    }
571
572    /// Generate man page for the man command itself
573    fn generate_man_man_page() -> Result<String> {
574        let current_date = Self::current_date();
575        let page = Roff::new()
576            .control("TH", ["VTCODE-MAN", "1", &current_date, "VT Code", "User Commands"])
577            .control("SH", ["NAME"])
578            .text([roman("vtcode-man - Generate or display man pages for VT Code commands")])
579            .control("SH", ["SYNOPSIS"])
580            .text([
581                bold("vtcode"),
582                roman(" ["),
583                bold("OPTIONS"),
584                roman("] "),
585                bold("man"),
586                roman(" ["),
587                italic("COMMAND"),
588                roman("] ["),
589                bold("--output"),
590                roman(" "),
591                italic("FILE"),
592                roman("]"),
593            ])
594            .control("SH", ["DESCRIPTION"])
595            .text([
596                roman("Generate or display Unix man pages for VT Code commands. Man pages provide"),
597                roman(" detailed documentation for all VT Code functionality including usage examples,"),
598                roman(" option descriptions, and feature explanations."),
599            ])
600            .control("SH", ["OPTIONS"])
601            .control("TP", [])
602            .text([bold("--output"), roman(" "), italic("FILE")])
603            .text([roman("Write man page to specified file instead of displaying")])
604            .control("SH", ["AVAILABLE COMMANDS"])
605            .text([roman("• chat - Interactive AI coding assistant")])
606            .text([roman("• ask - Single prompt mode")])
607            .text([roman("• analyze - Workspace analysis")])
608            .text([roman("• performance - Performance metrics")])
609            .text([roman("• trajectory - Pretty-print trajectory logs and analytics")])
610            .text([roman("• benchmark - SWE-bench evaluation framework")])
611            .text([roman("• create-project - Create complete Rust project with features")])
612
613            .text([roman("• revert - Revert agent to a previous snapshot")])
614            .text([roman("• snapshots - List available snapshots")])
615            .text([roman("• cleanup-snapshots - Clean up old snapshots")])
616            .text([roman("• init - Initialize project with enhanced structure")])
617            .text([roman("• init-project - Initialize project with dot-folder structure")])
618            .text([roman("• config - Generate configuration file")])
619            .text([roman("• tool-policy - Manage tool execution policies")])
620            .text([roman("• mcp - Manage Model Context Protocol providers")])
621            .text([roman("• models - Manage models and providers")])
622            .text([roman("• acp - Agent Client Protocol bridge for IDE integrations")])
623            .text([roman("• chat-verbose - Verbose interactive chat with transparency")])
624            .text([roman("• man - Man page generation (this command)")])
625            .control("SH", ["EXAMPLES"])
626            .text([roman("Display main VT Code man page:")])
627            .text([bold("  vtcode man")])
628            .text([roman("Display chat command man page:")])
629            .text([bold("  vtcode man chat")])
630            .text([roman("Save man page to file:")])
631            .text([bold("  vtcode man chat --output chat.1")])
632            .control("SH", ["SEE ALSO"])
633            .text([bold("vtcode(1)"), roman(", "), bold("man(1)")])
634            .render();
635
636        Ok(page)
637    }
638
639    /// Save man page to file
640    pub async fn save_man_page(content: &str, filename: &Path) -> Result<()> {
641        fs::write(filename, content)
642            .await
643            .with_context(|| format!("Failed to write man page to {}", filename.display()))?;
644        Ok(())
645    }
646
647    /// Get list of available commands for man page generation
648    pub fn available_commands() -> Vec<&'static str> {
649        vec![
650            "chat",
651            "ask",
652            "analyze",
653            "performance",
654            "benchmark",
655            "create-project",
656            "init",
657            "man",
658        ]
659    }
660}