use serde_json::Value;
use super::{OrchestratorBackend, required_str};
const DEFAULT_ACTIVITY_LINES: u32 = 60;
pub async fn try_dispatch<B: OrchestratorBackend>(
backend: &B,
name: &str,
args: &Value,
) -> Option<Result<Value, String>> {
let result = match name {
"session_new" => session_new(backend, args).await,
"session_stop" => match required_str(args, "session_id") {
Ok(id) => backend.session_stop(&id).await,
Err(e) => Err(e),
},
"session_resume" => match required_str(args, "session_id") {
Ok(id) => backend.session_resume(&id).await,
Err(e) => Err(e),
},
"session_decommission" => match required_str(args, "session_id") {
Ok(id) => backend.session_decommission(&id).await,
Err(e) => Err(e),
},
"session_delete" => match required_str(args, "session_id") {
Ok(id) => {
let force = args.get("force").and_then(Value::as_bool).unwrap_or(false);
backend.session_delete(&id, force).await
}
Err(e) => Err(e),
},
"session_activity" => match required_str(args, "session_id") {
Ok(id) => {
let lines = args
.get("lines")
.and_then(Value::as_u64)
.map(|n| n.min(u32::MAX as u64) as u32)
.unwrap_or(DEFAULT_ACTIVITY_LINES);
backend.session_activity(&id, lines).await
}
Err(e) => Err(e),
},
"session_send" => match (required_str(args, "session_id"), required_str(args, "text")) {
(Ok(id), Ok(text)) => backend.session_send(&id, &text).await,
(Err(e), _) | (_, Err(e)) => Err(e),
},
"session_context_catchup" => session_context_catchup(backend, args).await,
"session_context_pause" => session_context_pause(backend, args).await,
"session_decommission_ephemeral" => backend.session_decommission_ephemeral().await,
"session_prune" => match required_str(args, "state") {
Ok(state) => {
let dry_run = args
.get("dry_run")
.and_then(Value::as_bool)
.unwrap_or(false);
let include_active = args
.get("include_active")
.and_then(Value::as_bool)
.unwrap_or(false);
backend.session_prune(&state, dry_run, include_active).await
}
Err(e) => Err(e),
},
_ => return None,
};
Some(result)
}
async fn session_new<B: OrchestratorBackend>(backend: &B, args: &Value) -> Result<Value, String> {
let repo_url = required_str(args, "repo_url")?;
let git_ref = required_str(args, "ref")?;
let task = required_str(args, "task")?;
let name_hint = args.get("name_hint").and_then(Value::as_str);
let runtime = args.get("runtime").and_then(Value::as_str);
let ephemeral = args.get("ephemeral").and_then(Value::as_bool);
backend
.session_new(&repo_url, &git_ref, &task, name_hint, runtime, ephemeral)
.await
}
async fn session_context_catchup<B: OrchestratorBackend>(
backend: &B,
args: &Value,
) -> Result<Value, String> {
let project_dir = required_str(args, "project_dir")?;
let session_id = args.get("session_id").and_then(Value::as_str);
let all_projects = args
.get("all_projects")
.and_then(Value::as_bool)
.unwrap_or(false);
let full = args.get("full").and_then(Value::as_bool).unwrap_or(false);
backend
.session_context_catchup(&project_dir, session_id, all_projects, full)
.await
}
async fn session_context_pause<B: OrchestratorBackend>(
backend: &B,
args: &Value,
) -> Result<Value, String> {
let project_dir = required_str(args, "project_dir")?;
let session_id = required_str(args, "session_id")?;
let summary = required_str(args, "summary")?;
let completed = string_array(args, "completed");
let in_progress = string_array(args, "in_progress");
let next_steps = string_array(args, "next_steps");
let tmux_window = args.get("tmux_window").and_then(Value::as_str);
let prune_worktrees = args
.get("prune_worktrees")
.and_then(Value::as_bool)
.unwrap_or(true);
backend
.session_context_pause(
&project_dir,
&session_id,
&summary,
completed,
in_progress,
next_steps,
tmux_window,
prune_worktrees,
)
.await
}
fn string_array(args: &Value, key: &str) -> Vec<String> {
args.get(key)
.and_then(Value::as_array)
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(str::to_string))
.collect()
})
.unwrap_or_default()
}