1#[cfg(all(
30 windows,
31 not(all(
32 target_vendor = "pc",
33 target_env = "msvc",
34 any(target_arch = "x86_64", target_arch = "aarch64")
35 ))
36))]
37compile_error!(
38 "Pitboard for Windows is built for x86_64-pc-windows-msvc and aarch64-pc-windows-msvc \
39 alone, the targets it is built and tested on."
40);
41
42#[cfg(not(any(target_os = "macos", target_os = "linux", windows)))]
43compile_error!(
44 "Pitboard runs on macOS, Linux and Windows. Another system needs a host of its own in \
45 `host/`, saying where its stores, processes and scheduler are."
46);
47
48pub(crate) mod api;
49pub mod app;
50pub mod assumptions;
51pub mod audit;
52pub mod context;
53#[cfg(any(test, feature = "test-support"))]
55#[doc(hidden)]
56#[allow(
57 clippy::disallowed_methods,
58 reason = "it leaves Claude Desktop's files as Claude does"
59)]
60pub mod desktop_testing;
61pub mod doctor;
62pub mod duty;
63pub mod error;
64pub(crate) mod in_use;
65pub mod label;
66pub mod provider;
67pub mod redact;
68pub mod release;
69pub mod schedule;
70pub mod service;
71pub(crate) mod settings;
72pub mod state;
73pub mod status;
74pub mod statusline;
75pub mod switch;
76pub mod time;
77pub mod usage;
78pub mod words;
79
80pub(crate) mod atomic;
81pub(crate) mod base64;
82pub(crate) mod fault;
83#[cfg(test)]
84mod helper;
85pub mod holder;
86pub(crate) mod home;
87pub mod host;
88pub(crate) mod lock;
89pub(crate) mod park;
90pub(crate) mod pending;
91pub(crate) mod proxy;
92pub(crate) mod sessions;
93#[cfg(any(test, feature = "test-support"))]
96#[doc(hidden)]
97pub mod stand_in;
98pub(crate) mod store;
99
100#[cfg(feature = "test-support")]
103#[doc(hidden)]
104pub mod testing {
105 pub use crate::api::scripted::{Answer, Asked, ScriptedApi, Trouble};
106 pub use crate::desktop_testing as desktop;
107 pub use crate::duty::warm::run::{Started, WarmScript};
108 pub use crate::host::Ran;
109 pub use crate::host::fs::testing as fs;
113 pub use crate::host::memory::MemoryHost;
114 pub use crate::provider::claude::api::Renewed;
115 pub use crate::provider::claude::paths::live_service;
116 pub use crate::provider::claude::slot::{LIVE_SERVICE, dir_hash, service_for_dir};
117 pub use crate::stand_in;
120 pub use crate::store::memory::{Fault, MemoryStore};
121 pub use crate::store::vault_read;
122 pub use crate::switch::enroll::{ScriptedSignIn, SignInScript};
123 pub use crate::time::{Clock, FixedClock};
124
125 pub fn variables() -> impl Iterator<Item = &'static str> {
128 crate::context::variables()
129 }
130
131 pub fn lies_in(path: &std::path::Path, place: &std::path::Path) -> bool {
133 crate::host::lies_in(path, place)
134 }
135
136 pub fn real_login_places(
137 started_in: &crate::context::Context,
138 ) -> Result<Vec<std::path::PathBuf>, String> {
139 crate::host::real_login_places(Some(started_in))
140 }
141
142 pub fn vault_write(
145 ctx: &crate::context::Context,
146 service: &str,
147 contents: &str,
148 ) -> crate::error::Result<()> {
149 let permit = crate::service::gate(ctx)?;
150 Ok(crate::store::vault_write(ctx, permit, service, contents)?)
151 }
152
153 pub fn may_be_running(pid: u32) -> bool {
154 crate::host::proc::may_be_running(pid)
155 }
156
157 #[cfg(windows)]
159 pub fn processes() -> std::io::Result<Vec<(u32, u32, String)>> {
160 crate::host::proc::snapshot()
161 }
162
163 #[cfg(windows)]
165 pub mod version_resource {
166 use std::path::Path;
167
168 pub fn file_version(program: &Path) -> Option<[u16; 4]> {
169 crate::host::proc::file_version(program)
170 }
171
172 pub fn product_version(program: &Path) -> Option<[u16; 4]> {
173 crate::host::proc::product_version(program)
174 }
175
176 pub fn string(program: &Path, name: &str) -> Option<String> {
177 crate::host::proc::version_string(program, name)
178 }
179 }
180
181 #[cfg(windows)]
184 pub mod credman {
185 use crate::context::Context;
186 use crate::store::RawStore;
187
188 pub struct Item {
189 pub kind: u32,
190 pub persist: u32,
191 pub user: String,
192 pub comment: Option<String>,
193 pub attributes: u32,
194 pub bytes: usize,
195 }
196
197 fn refused(target: &str) -> std::io::Result<()> {
198 match crate::provider::names::refusal(target, &[]) {
199 Some(why) => Err(std::io::Error::other(why)),
200 None => Ok(()),
201 }
202 }
203
204 pub fn item(target: &str) -> std::io::Result<Option<Item>> {
205 refused(target)?;
206 Ok(
207 crate::host::windows_credman::item(target)?.map(|held| Item {
208 kind: held.kind,
209 persist: held.persist,
210 user: held.user,
211 comment: held.comment,
212 attributes: held.attributes,
213 bytes: held.blob.len(),
214 }),
215 )
216 }
217
218 pub fn write_as_bun(target: &str, user: &str, value: &str) -> std::io::Result<()> {
220 refused(target)?;
221 crate::host::windows_credman::write(target, user, value.as_bytes())
222 }
223
224 fn store(ctx: &Context) -> crate::provider::claude::credman::Store {
225 crate::provider::claude::credman::Store::of(ctx)
226 }
227
228 pub fn write(ctx: &Context, service: &str, contents: &str) -> crate::error::Result<()> {
229 let permit = crate::service::gate(ctx)?;
230 Ok(store(ctx).write(permit, service, contents)?)
231 }
232
233 pub fn read(ctx: &Context, service: &str) -> crate::error::Result<Option<String>> {
234 Ok(store(ctx).read(service)?)
235 }
236
237 pub fn discard(ctx: &Context, service: &str) -> crate::error::Result<()> {
239 let permit = crate::service::gate(ctx)?;
240 Ok(store(ctx).delete(permit, service)?)
241 }
242
243 pub fn sweep(ctx: &Context, service: &str) -> Result<(), String> {
245 crate::provider::claude::credman::swept(ctx, service)
246 }
247 }
248
249 pub fn vault_delete(ctx: &crate::context::Context, service: &str) -> crate::error::Result<()> {
251 let permit = crate::service::gate(ctx)?;
252 Ok(crate::store::vault_delete(ctx, permit, service)?)
253 }
254
255 pub fn signed_in(
260 ctx: &crate::context::Context,
261 which: crate::provider::ProviderId,
262 document: &str,
263 ) -> crate::error::Result<crate::switch::SignIn> {
264 use crate::provider::LoginKind;
265 let document = serde_json::from_str(document).expect("a login a test wrote as JSON");
266 match crate::provider::of(which) {
267 LoginKind::Document(tool) => {
268 crate::switch::planted(ctx, crate::service::gate(ctx)?, tool, document)
269 }
270 LoginKind::Folder(_) => Err(crate::error::Error::Usage(
271 "a Claude Desktop sign-in is played by testing::desktop".into(),
272 )),
273 }
274 }
275}