use serde::{Deserialize, Serialize};
use car_automation::{applescript, shortcuts, AutomationOutput};
#[derive(Debug, Deserialize)]
pub struct RunAppleScriptArgs {
pub script: String,
#[serde(default)]
pub language: Option<String>,
#[serde(default)]
pub args: Vec<String>,
#[serde(default)]
pub timeout_ms: Option<u64>,
}
#[derive(Debug, Serialize)]
pub struct AutomationOutputJson {
pub stdout: String,
pub stderr: String,
pub exit_code: Option<i32>,
}
impl From<AutomationOutput> for AutomationOutputJson {
fn from(o: AutomationOutput) -> Self {
Self {
stdout: o.stdout,
stderr: o.stderr,
exit_code: o.exit_code,
}
}
}
pub async fn run_applescript(args_json: &str) -> Result<String, String> {
let args: RunAppleScriptArgs =
serde_json::from_str(args_json).map_err(|e| format!("invalid args: {e}"))?;
let lang = match args.language.as_deref() {
Some("javascript") | Some("jxa") => applescript::Language::JavaScript,
_ => applescript::Language::AppleScript,
};
let timeout = args.timeout_ms.map(std::time::Duration::from_millis);
let arg_refs: Vec<&str> = args.args.iter().map(String::as_str).collect();
let out = applescript::run_with_args(&args.script, lang, &arg_refs, timeout)
.await
.map_err(|e| format!("{e}"))?;
Ok(serde_json::to_string(&AutomationOutputJson::from(out))
.map_err(|e| format!("serialize: {e}"))?)
}
#[derive(Debug, Deserialize)]
pub struct ListShortcutsArgs {
#[serde(default)]
pub folder: Option<String>,
#[serde(default)]
pub with_identifiers: bool,
}
#[derive(Debug, Serialize)]
pub struct ShortcutJson {
pub name: String,
pub identifier: Option<String>,
pub tool_slug: String,
pub tool_description: String,
pub parameters_schema: serde_json::Value,
}
impl From<shortcuts::Shortcut> for ShortcutJson {
fn from(s: shortcuts::Shortcut) -> Self {
let tool_slug = s.tool_slug();
let tool_description = s.tool_description();
let parameters_schema = s.parameters_schema();
Self {
name: s.name,
identifier: s.identifier,
tool_slug,
tool_description,
parameters_schema,
}
}
}
pub async fn list_shortcuts(args_json: &str) -> Result<String, String> {
let args: ListShortcutsArgs =
serde_json::from_str(args_json).map_err(|e| format!("invalid args: {e}"))?;
let list = shortcuts::list(args.folder.as_deref(), args.with_identifiers)
.await
.map_err(|e| format!("{e}"))?;
let json: Vec<ShortcutJson> = list.into_iter().map(Into::into).collect();
serde_json::to_string(&json).map_err(|e| format!("serialize: {e}"))
}
#[derive(Debug, Deserialize)]
pub struct RunShortcutArgs {
pub name_or_id: String,
#[serde(default)]
pub input: Option<String>,
#[serde(default)]
pub output_type: Option<String>,
#[serde(default)]
pub timeout_ms: Option<u64>,
}
pub async fn run_shortcut(args_json: &str) -> Result<String, String> {
let args: RunShortcutArgs =
serde_json::from_str(args_json).map_err(|e| format!("invalid args: {e}"))?;
let timeout = args.timeout_ms.map(std::time::Duration::from_millis);
let input_bytes = args.input.as_ref().map(|s| s.as_bytes());
let out = shortcuts::run(
&args.name_or_id,
input_bytes,
args.output_type.as_deref(),
timeout,
)
.await
.map_err(|e| format!("{e}"))?;
serde_json::to_string(&AutomationOutputJson::from(out))
.map_err(|e| format!("serialize: {e}"))
}