use crate::actions::verbs::Verb as BallVerb;
use crate::boundary::{Action, Gesture};
mod queries;
use crate::start::{BallSpec, Payload};
use queries::spell_query;
pub fn spell(gesture: &Gesture) -> String {
match gesture {
Gesture::Act(action) => spell_action(action),
Gesture::Ask(query) => spell_query(query),
}
}
fn spell_action(action: &Action) -> String {
match action {
Action::Message { content, .. } => format!("/message {content}"),
Action::Interrupt { content, .. } => format!("/interrupt {content}"),
Action::Stop { children, .. } => match children {
true => "/stop children".to_owned(),
false => "/stop".to_owned(),
},
Action::Scan { .. } => "/scan".to_owned(),
Action::Nudge { .. } => "/nudge".to_owned(),
Action::Retarget { .. } => "/retarget".to_owned(),
Action::Ball(verb) => spell_ball(verb),
Action::Prepare { payload, .. } => spell_payload(payload),
Action::Prompt { goal, .. } => format!("/prompt {goal}"),
Action::Fan(crate::fan::Verb::Spread { n, .. }) => format!("/fan {n}"),
Action::Fan(crate::fan::Verb::Retire { handle, .. }) => format!("/retire {handle}"),
Action::Fan(crate::fan::Verb::Deliver {
handle, summary, ..
}) => {
format!("/deliver {handle} {summary}")
}
Action::DeleteWorkspace { typed, .. } => format!("/delete-workspace {typed}"),
Action::DeleteAgent { typed, .. } if typed.is_empty() => "/delete-agent".to_owned(),
Action::DeleteAgent { typed, .. } => format!("/delete-agent {typed}"),
Action::Monitor(verb) => spell_monitor(verb),
Action::Fleet(verb) => spell_fleet(verb),
Action::AnswerHold { ruling, .. } => format!("/answer {}", ruling.word()),
Action::Floor { raised, .. } => match raised {
true => "/revoke".to_owned(),
false => "/restore".to_owned(),
},
Action::ApplyConfig { file, text } => {
format!("/config {} {text}", super::config::target_words(file))
}
Action::SetMarks { branch, .. } => format!("/marks {branch}"),
Action::PickModel {
role,
provider,
model,
..
} => format!("/model {role} {provider} {model}"),
Action::Tune(tuning) => spell_tuning(tuning),
Action::Login { provider, .. } => {
format!("/{} {provider}", crate::boundary::codec::LOGIN)
}
Action::Fork { attempt, goal, .. } => super::fork::spell(attempt, goal),
Action::Ack => "/ack".to_owned(),
Action::MarkSeen { .. } => "/seen".to_owned(),
Action::Pin { pinned, .. } => {
format!("/{}", if *pinned { "pin" } else { "unpin" })
}
Action::ClearTrail => "/clear-trail".to_owned(),
Action::Advertise { tools } => {
format!("/advertise {}", crate::registry::tools::encode(tools))
}
Action::Enroll(request) => match request.grade {
crate::registry::Grade::Operator => {
format!("/{} {}", crate::boundary::codec::ENROLL, request.name)
}
grade @ crate::registry::Grade::Foot => format!(
"/{} {} {}",
crate::boundary::codec::ENROLL,
request.name,
grade.word()
),
},
Action::Route(verb) => spell_route(verb),
}
}
fn spell_route(verb: &crate::registry::mailbox::Verb) -> String {
use crate::registry::mailbox::{Verb, capture_value};
match verb {
Verb::Invoke(call) => match &call.cwd {
Some(cwd) => format!(
"/invoke {} {} --cwd {} {}",
call.client, call.tool, cwd, call.input
),
None => format!("/invoke {} {} {}", call.client, call.tool, call.input),
},
Verb::Complete(done) => format!(
"/complete {} {}",
done.invocation,
capture_value(&done.capture)
),
}
}
fn spell_monitor(verb: &crate::monitor::Verb) -> String {
use crate::monitor::Verb;
match verb {
Verb::Arm { model, .. } => format!("/arm {model}"),
Verb::Disarm { .. } => "/disarm".to_owned(),
Verb::Flag { reason, .. } => format!("/flag {reason}"),
}
}
fn spell_ball(verb: &BallVerb) -> String {
match verb {
BallVerb::Close { id, .. } => format!("/close {id}"),
BallVerb::Assign { id, .. } => format!("/assign {id}"),
BallVerb::Release { id, .. } => format!("/release {id}"),
BallVerb::Create { fields, .. } => format!(
"/create {}{}{}",
fields.title,
flag("body", fields.body.as_ref()),
super::balls::spell_fields(&fields.fields)
),
BallVerb::Update { id, fields, .. } => format!(
"/update {id}{}{}{}{}",
flag("title", fields.title.as_ref()),
flag("body", fields.body.as_ref()),
flag("note", fields.note.as_ref()),
super::balls::spell_fields(&fields.fields)
),
}
}
fn spell_tuning(tuning: &crate::model_pick::Tuning) -> String {
use crate::model_pick::Tuning;
match tuning {
Tuning::Effort { role, level, .. } => {
let word = level.map_or_else(|| "off".to_owned(), |l| l.as_str());
format!("/effort {role} {word}")
}
Tuning::Priority { role, on, .. } => {
format!("/priority {role} {}", if *on { "on" } else { "off" })
}
}
}
fn spell_fleet(verb: &crate::fleet::Verb) -> String {
use crate::fleet::Verb;
match verb {
Verb::Arm { cap, .. } => format!("/{} {cap}", crate::boundary::codec::FLEET_ARM),
Verb::Disarm { .. } => format!("/{}", crate::boundary::codec::FLEET_DISARM),
}
}
fn spell_payload(payload: &Payload) -> String {
match payload {
Payload::Bare => "/prepare".to_owned(),
Payload::Path { dir } => format!("/prepare dir {}", dir.display()),
Payload::Ball { ball, .. } => match ball {
BallSpec::Existing { .. } => "/prepare ball".to_owned(),
BallSpec::New { title, body } => format!(
"/prepare ball --new {title}{}",
flag("body", Some(body).filter(|b| !b.is_empty()))
),
},
}
}
fn flag(key: &str, value: Option<&String>) -> String {
match value {
Some(text) => format!(" --{key} {text}"),
None => String::new(),
}
}