hivemind/adapters/
claude_code.rs1use super::opencode::{OpenCodeAdapter, OpenCodeConfig};
4use super::runtime::{
5 AdapterConfig, ExecutionInput, ExecutionReport, InteractiveAdapterEvent,
6 InteractiveExecutionResult, RuntimeAdapter, RuntimeError,
7};
8use std::path::PathBuf;
9use std::time::Duration;
10use uuid::Uuid;
11
12#[derive(Debug, Clone)]
14pub struct ClaudeCodeConfig {
15 pub base: AdapterConfig,
17 pub model: Option<String>,
19}
20
21impl ClaudeCodeConfig {
22 pub fn new(binary_path: PathBuf) -> Self {
24 Self {
25 base: AdapterConfig::new("claude-code", binary_path)
26 .with_timeout(Duration::from_secs(600)),
27 model: None,
28 }
29 }
30
31 #[must_use]
33 pub fn with_model(mut self, model: impl Into<String>) -> Self {
34 self.model = Some(model.into());
35 self
36 }
37}
38
39impl Default for ClaudeCodeConfig {
40 fn default() -> Self {
41 let mut cfg = Self::new(PathBuf::from("claude"));
42 cfg.base.args = vec!["-p".to_string()];
43 cfg
44 }
45}
46
47pub struct ClaudeCodeAdapter {
49 inner: OpenCodeAdapter,
50}
51
52impl ClaudeCodeAdapter {
53 pub fn new(config: ClaudeCodeConfig) -> Self {
55 let mut inner = OpenCodeConfig::new(config.base.binary_path.clone());
56 inner.base.name = "claude-code".to_string();
57 inner.base.args = config.base.args;
58 inner.base.env = config.base.env;
59 inner.base.timeout = config.base.timeout;
60 inner.model.clone_from(&config.model);
61
62 if let Some(model) = config.model {
63 let has_model_flag = inner
64 .base
65 .args
66 .iter()
67 .any(|a| a == "--model" || a.starts_with("--model="));
68 if !has_model_flag {
69 inner.base.args.extend(["--model".to_string(), model]);
70 }
71 }
72
73 Self {
74 inner: OpenCodeAdapter::new(inner),
75 }
76 }
77
78 pub fn with_defaults() -> Self {
80 Self::new(ClaudeCodeConfig::default())
81 }
82
83 pub fn execute_interactive<F>(
84 &mut self,
85 input: &ExecutionInput,
86 on_event: F,
87 ) -> Result<InteractiveExecutionResult, RuntimeError>
88 where
89 F: FnMut(InteractiveAdapterEvent) -> std::result::Result<(), String>,
90 {
91 self.inner.execute_interactive(input, on_event)
92 }
93}
94
95impl RuntimeAdapter for ClaudeCodeAdapter {
96 fn name(&self) -> &str {
97 self.inner.name()
98 }
99
100 fn initialize(&mut self) -> Result<(), RuntimeError> {
101 self.inner.initialize()
102 }
103
104 fn prepare(&mut self, task_id: Uuid, worktree: &std::path::Path) -> Result<(), RuntimeError> {
105 self.inner.prepare(task_id, worktree)
106 }
107
108 fn execute(&mut self, input: ExecutionInput) -> Result<ExecutionReport, RuntimeError> {
109 self.inner.execute(input)
110 }
111
112 fn terminate(&mut self) -> Result<(), RuntimeError> {
113 self.inner.terminate()
114 }
115
116 fn config(&self) -> &AdapterConfig {
117 self.inner.config()
118 }
119}