Skip to main content

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}