1#![cfg_attr(
2 not(test),
3 deny(clippy::unwrap_used, clippy::panic, clippy::indexing_slicing)
4)]
5#![cfg_attr(test, allow(clippy::disallowed_methods))]
9pub use doctor::DoctorChecks;
59pub use license::LicenseType;
60pub use types::{DoctorCheck, RepoInfo};
61
62pub mod agent;
64pub mod agent_skill;
65pub mod app;
66pub mod binary;
67pub mod command;
68pub mod completions;
69pub mod doctor;
70pub mod error;
71pub mod json;
72pub mod license;
73pub mod meta;
74pub mod output;
75pub mod progress;
76pub mod runner;
77pub mod types;
78
79pub use agent::{
81 AGENT_TOKEN_ENV, AGENT_TOKEN_EXPECTED_ENV, AgentCapability, AgentDispatch, AgentModeContext,
82 AgentSkillError, AgentSurfaceSpec, CommandSelector, FlagSelector, ProcessEnv,
83 apply_agent_surface, parse_with_agent_surface_from, render_agent_help, render_agent_skill,
84};
85pub use agent::{AgentSubcommand, DescribeFormat, EmitScope, EmitTarget, ListFormat};
86pub use agent_skill::{
87 EmitDirError, render_describe, render_list, render_skill_md, resolve_emit_dir,
88 run_agent_subcommand, skill_name,
89};
90pub use app::{ContractError, ToolContract, ToolSpec, workspace_tool};
91pub use binary::{run_cli_from, run_cli_no_doctor_from};
92pub use command::{
93 NoDoctor, StandardCommand, StandardCommandMap, map_standard_command,
94 maybe_run_standard_command, maybe_run_standard_command_no_doctor,
95 parse_command_ref_with_agent_surface_from, parse_command_with_agent_surface_from,
96 run_standard_command_no_doctor,
97};
98pub use completions::{
99 CompletionOutput, generate_completions, generate_completions_from_command, render_completion,
100 render_completion_from_command, render_completion_instructions, write_completion,
101};
102pub use doctor::{
103 DoctorReport, print_doctor_report_json, print_doctor_report_text, run_doctor,
104 run_doctor_with_output,
105};
106pub use error::{fatal_error, print_error};
107pub use json::{
108 JsonOutput, err_response, ok_response, render_response, render_response_parts,
109 render_response_with,
110};
111pub use license::display_license;
112pub use meta::MetaCommand;
113pub use progress::make_spinner;
114pub use runner::{
115 FatalCliError, parse_and_exit, parse_and_run, run_with_display_error_handler,
116 run_with_fatal_handler,
117};
118
119#[cfg(test)]
120pub mod test_support {
122 use std::sync::{Mutex, MutexGuard, OnceLock};
123
124 static ENV_LOCK: OnceLock<Mutex<()>> = OnceLock::new();
125
126 pub fn env_lock() -> MutexGuard<'static, ()> {
128 ENV_LOCK
129 .get_or_init(|| Mutex::new(()))
130 .lock()
131 .unwrap_or_else(std::sync::PoisonError::into_inner)
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_repo_info_creation() {
141 let repo = RepoInfo::new("workhelix", "test");
142 assert_eq!(repo.owner, "workhelix");
143 assert_eq!(repo.name, "test");
144 }
145
146 #[test]
147 fn test_doctor_check_creation() {
148 let check = DoctorCheck::pass("test");
149 assert!(check.passed);
150
151 let check = DoctorCheck::fail("test", "failed");
152 assert!(!check.passed);
153 }
154
155 #[test]
156 fn test_license_type() {
157 assert_eq!(LicenseType::MIT.name(), "MIT");
158 assert_eq!(LicenseType::Apache2.name(), "Apache-2.0");
159 assert_eq!(LicenseType::CC0.name(), "CC0-1.0");
160 }
161}