1#![forbid(unsafe_code)]
2use std::{
8 future::Future,
9 pin::Pin,
10 sync::{
11 atomic::{AtomicBool, Ordering},
12 Arc,
13 },
14};
15
16use futures_core::Stream;
17use tokio::sync::Notify;
18
19mod builder;
20mod cli;
21mod client;
22mod commands;
23mod error;
24mod home;
25mod process;
26mod stream_json;
27pub mod wrapper_coverage_manifest;
28
29pub use builder::ClaudeClientBuilder;
30pub use client::ClaudeClient;
31pub use client::ClaudeSetupTokenSession;
32pub use commands::command::ClaudeCommandRequest;
33pub use commands::doctor::ClaudeDoctorRequest;
34pub use commands::mcp::{
35 McpAddFromClaudeDesktopRequest, McpAddJsonRequest, McpAddRequest, McpGetRequest,
36 McpRemoveRequest, McpScope, McpServeRequest, McpTransport,
37};
38pub use commands::plugin::{
39 PluginDisableRequest, PluginEnableRequest, PluginInstallRequest, PluginListRequest,
40 PluginManifestMarketplaceRequest, PluginManifestRequest, PluginMarketplaceAddRequest,
41 PluginMarketplaceListRequest, PluginMarketplaceRemoveRequest, PluginMarketplaceRepoRequest,
42 PluginMarketplaceRequest, PluginMarketplaceUpdateRequest, PluginRequest,
43 PluginUninstallRequest, PluginUpdateRequest, PluginValidateRequest,
44};
45pub use commands::print::{
46 ClaudeChromeMode, ClaudeInputFormat, ClaudeOutputFormat, ClaudePrintRequest,
47};
48pub use commands::setup_token::ClaudeSetupTokenRequest;
49pub use commands::update::ClaudeUpdateRequest;
50pub use error::{ClaudeCodeError, StreamJsonLineError};
51pub use home::{
52 ClaudeHomeLayout, ClaudeHomeSeedLevel, ClaudeHomeSeedOutcome, ClaudeHomeSeedRequest,
53};
54pub use stream_json::{parse_stream_json_lines, StreamJsonLine, StreamJsonLineOutcome};
55pub use stream_json::{
56 ClaudeStreamEvent, ClaudeStreamJsonErrorCode, ClaudeStreamJsonEvent,
57 ClaudeStreamJsonParseError, ClaudeStreamJsonParser,
58};
59
60pub use process::CommandOutput;
61
62pub type DynClaudeStreamJsonEventStream =
63 Pin<Box<dyn Stream<Item = Result<ClaudeStreamJsonEvent, ClaudeStreamJsonParseError>> + Send>>;
64
65pub type DynClaudeStreamJsonCompletion =
66 Pin<Box<dyn Future<Output = Result<std::process::ExitStatus, ClaudeCodeError>> + Send>>;
67
68#[derive(Clone)]
69pub struct ClaudeTerminationHandle {
70 inner: Arc<ClaudeTerminationInner>,
71}
72
73#[derive(Debug)]
74struct ClaudeTerminationInner {
75 requested: AtomicBool,
76 notify: Notify,
77}
78
79impl ClaudeTerminationHandle {
80 fn new() -> Self {
81 Self {
82 inner: Arc::new(ClaudeTerminationInner {
83 requested: AtomicBool::new(false),
84 notify: Notify::new(),
85 }),
86 }
87 }
88
89 pub fn request_termination(&self) {
90 if !self.inner.requested.swap(true, Ordering::SeqCst) {
91 self.inner.notify.notify_waiters();
92 }
93 }
94
95 fn is_requested(&self) -> bool {
96 self.inner.requested.load(Ordering::SeqCst)
97 }
98
99 async fn requested(&self) {
100 if self.is_requested() {
101 return;
102 }
103
104 let notified = self.inner.notify.notified();
105 if self.is_requested() {
106 return;
107 }
108
109 notified.await;
110 }
111}
112
113impl std::fmt::Debug for ClaudeTerminationHandle {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 f.debug_struct("ClaudeTerminationHandle")
116 .field("requested", &self.is_requested())
117 .finish()
118 }
119}
120
121pub struct ClaudePrintStreamJsonHandle {
122 pub events: DynClaudeStreamJsonEventStream,
123 pub completion: DynClaudeStreamJsonCompletion,
124}
125
126impl std::fmt::Debug for ClaudePrintStreamJsonHandle {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 f.debug_struct("ClaudePrintStreamJsonHandle")
129 .field("events", &"<stream>")
130 .field("completion", &"<future>")
131 .finish()
132 }
133}
134
135pub struct ClaudePrintStreamJsonControlHandle {
136 pub events: DynClaudeStreamJsonEventStream,
137 pub completion: DynClaudeStreamJsonCompletion,
138 pub termination: ClaudeTerminationHandle,
139}
140
141impl std::fmt::Debug for ClaudePrintStreamJsonControlHandle {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 f.debug_struct("ClaudePrintStreamJsonControlHandle")
144 .field("events", &"<stream>")
145 .field("completion", &"<future>")
146 .field("termination", &self.termination)
147 .finish()
148 }
149}