ito_core/harness/github_copilot.rs
1use super::streaming_cli::run_streaming_cli;
2use super::types::{Harness, HarnessName, HarnessRunConfig, HarnessRunResult};
3use miette::Result;
4
5/// Runs the `copilot` CLI in non-interactive print mode (`copilot -p`).
6/// Selected via `ito ralph --harness copilot`; requires the Copilot CLI on PATH.
7#[derive(Debug, Default)]
8pub struct GitHubCopilotHarness;
9
10impl Harness for GitHubCopilotHarness {
11 /// Identify this harness as the GitHub Copilot harness.
12 ///
13 /// # Returns
14 ///
15 /// `HarnessName::GITHUB_COPILOT`.
16 ///
17 /// # Examples
18 ///
19 /// ```
20 /// use ito_core::harness::{GitHubCopilotHarness, Harness, HarnessName};
21 ///
22 /// let h = GitHubCopilotHarness::default();
23 /// assert_eq!(h.name(), HarnessName::GITHUB_COPILOT);
24 /// ```
25 fn name(&self) -> HarnessName {
26 HarnessName::GITHUB_COPILOT
27 }
28
29 /// Execute the GitHub Copilot CLI using values from the provided run configuration.
30 ///
31 /// The function builds CLI arguments from `config` (adds `--model <model>` when `config.model` is set,
32 /// adds `--yolo` when `config.allow_all` is true, and passes the prompt with `-p <prompt>`),
33 /// then delegates execution to the streaming CLI and returns its `HarnessRunResult`.
34 ///
35 /// # Examples
36 ///
37 /// ```rust,ignore
38 /// let mut harness = GitHubCopilotHarness::default();
39 /// let config = HarnessRunConfig {
40 /// model: Some("gpt-copilot-1".to_string()),
41 /// allow_all: true,
42 /// prompt: "Fix the failing tests".to_string(),
43 /// ..Default::default()
44 /// };
45 /// let result = harness.run(&config)?;
46 /// ```
47 fn run(&mut self, config: &HarnessRunConfig) -> Result<HarnessRunResult> {
48 let mut args = Vec::new();
49 if let Some(model) = config.model.as_deref() {
50 args.push("--model".to_string());
51 args.push(model.to_string());
52 }
53 if config.allow_all {
54 args.push("--yolo".to_string());
55 }
56 args.push("-p".to_string());
57 args.push(config.prompt.clone());
58
59 run_streaming_cli("copilot", &args, config)
60 }
61
62 /// Stops the harness; a no-op for GitHubCopilotHarness because `run` is synchronous.
63 ///
64 /// # Examples
65 ///
66 /// ```
67 /// use ito_core::harness::{GitHubCopilotHarness, Harness};
68 ///
69 /// let mut h = GitHubCopilotHarness::default();
70 /// h.stop();
71 /// ```
72 fn stop(&mut self) {
73 // No-op: `run` is synchronous.
74 }
75
76 /// Indicates whether this harness produces streaming output.
77 ///
78 /// # Returns
79 ///
80 /// `true` if the harness produces streaming output, `false` otherwise.
81 ///
82 /// # Examples
83 ///
84 /// ```
85 /// use ito_core::harness::{GitHubCopilotHarness, Harness};
86 ///
87 /// let h = GitHubCopilotHarness::default();
88 /// assert!(h.streams_output());
89 /// ```
90 fn streams_output(&self) -> bool {
91 true
92 }
93}