claude_code_cli_acp/
print_mode.rs1use std::{path::PathBuf, str::FromStr, time::Duration};
2
3use clap::ValueEnum;
4use serde::Serialize;
5use uuid::Uuid;
6
7use crate::session::manager::{ManagedSession, SessionManager, TurnOptions};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
10pub enum OutputFormat {
11 Text,
12 Json,
13 StreamJson,
14}
15
16impl FromStr for OutputFormat {
17 type Err = String;
18
19 fn from_str(value: &str) -> Result<Self, Self::Err> {
20 match value {
21 "text" => Ok(Self::Text),
22 "json" => Ok(Self::Json),
23 "stream-json" => Ok(Self::StreamJson),
24 other => Err(format!("unsupported output format: {other}")),
25 }
26 }
27}
28
29#[derive(Debug, Clone)]
30pub struct PrintRequest {
31 pub prompt: String,
32 pub output_format: OutputFormat,
33 pub resume: Option<String>,
34 pub continue_last: bool,
35 pub session_id: Option<String>,
36 pub cwd: Option<PathBuf>,
37 pub model: Option<String>,
38 pub permission_mode: Option<String>,
39 pub timeout: Duration,
40 pub attach_on_timeout: bool,
41 pub attach_on_permission: bool,
42}
43
44#[derive(Debug, Serialize)]
45struct JsonOutput {
46 session_id: String,
47 text: String,
48 model: Option<String>,
49}
50
51pub async fn run(request: PrintRequest) -> anyhow::Result<()> {
52 let cwd = request.cwd.clone().unwrap_or(std::env::current_dir()?);
53 let session_id = request
54 .session_id
55 .clone()
56 .unwrap_or_else(|| Uuid::new_v4().to_string());
57 let manager = SessionManager::new();
58 let session = manager.create_print_session(session_id.clone(), cwd, request.model.clone())?;
59 let turn = session
60 .prompt(
61 request.prompt,
62 TurnOptions {
63 timeout: request.timeout,
64 model: request.model,
65 permission_mode: request.permission_mode,
66 resume: request.resume,
67 continue_last: request.continue_last,
68 initial_prompt_argument: false,
69 attach_on_timeout: request.attach_on_timeout,
70 attach_on_permission: request.attach_on_permission,
71 },
72 )
73 .await?;
74 let emit_result = emit_output(
75 request.output_format,
76 &session,
77 &turn.final_text(),
78 turn.model(),
79 )
80 .await;
81 let shutdown_result = session.shutdown().await;
82 emit_result?;
83 shutdown_result
84}
85
86async fn emit_output(
87 format: OutputFormat,
88 session: &ManagedSession,
89 text: &str,
90 model: Option<String>,
91) -> anyhow::Result<()> {
92 match format {
93 OutputFormat::Text => {
94 write_stdout(format!("{text}\n"))?;
95 }
96 OutputFormat::Json => {
97 write_stdout(format!(
98 "{}\n",
99 serde_json::to_string(&JsonOutput {
100 session_id: session.session_id().0.to_string(),
101 text: text.to_string(),
102 model,
103 })?
104 ))?;
105 }
106 OutputFormat::StreamJson => {
107 write_stdout(format!(
108 "{}\n",
109 serde_json::to_string(&serde_json::json!({
110 "type": "message",
111 "session_id": session.session_id().0.to_string(),
112 "text": text,
113 "model": model,
114 }))?
115 ))?;
116 }
117 }
118 Ok(())
119}
120
121fn write_stdout(output: String) -> anyhow::Result<()> {
122 use std::io::Write;
123 std::io::stdout().write_all(output.as_bytes())?;
124 Ok(())
125}