use crate::actions::verbs::Outcome;
use crate::binding::Workspace;
use crate::board::Board;
use crate::nav::convs::ConvRow;
use crate::opslog::OpRow;
use crate::projects::join::JoinRow;
use crate::search::Found;
use crate::start::Prepared;
use serde_json::{Map, Value, json};
use std::path::PathBuf;
use super::codec::prepared_value;
mod board;
mod queue;
mod rows;
use board::{board_row, fleet_facts};
use queue::queue_row;
use rows::{conv_row, join_row, op_row, ws_row};
mod search;
use search::hit_row;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WsRow {
pub workspace: Workspace,
pub attention: usize,
pub agents: usize,
pub running: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Reply {
Outcome(Outcome),
Prepared(Prepared),
Started {
conversation: String,
},
Deleted,
Armed {
armed: bool,
},
Flagged,
Answered {
tool_use: String,
tool: String,
ruling: crate::control::judge::Ruling,
advanced: bool,
},
Floored {
standing: bool,
},
Acked,
TrailCleared,
Applied {
file: String,
},
Marks {
branch: String,
space: PathBuf,
},
Workspaces(Vec<WsRow>),
Conversations(Vec<ConvRow>),
Balls(Vec<JoinRow>),
Board(Board),
Attention(Vec<crate::boundary::answer::queue::QueueRow>),
Ops(Vec<OpRow>),
Help(Vec<crate::boundary::help::HelpRow>),
Search(Found),
WorkDiff {
attempts: Vec<crate::workdiff::Attempt>,
patch: Option<crate::files_view::Preview>,
},
Config {
text: String,
},
Providers(Vec<crate::config_edit::brazen::ProviderRowView>),
}
pub fn encode(reply: &Reply) -> Value {
match reply {
Reply::Outcome(outcome) => json!({
"ok": outcome.ok(), "kind": "outcome", "exit": outcome.exit,
"stdout": outcome.stdout, "stderr": outcome.stderr,
}),
Reply::Prepared(prepared) => {
json!({ "ok": true, "kind": "prepared", "prepared": prepared_value(prepared) })
}
Reply::Started { conversation } => {
json!({ "ok": true, "kind": "started", "conversation": conversation })
}
Reply::Deleted => json!({ "ok": true, "kind": "deleted" }),
Reply::Armed { armed } => json!({ "ok": true, "kind": "armed", "armed": armed }),
Reply::Flagged => json!({ "ok": true, "kind": "flagged" }),
Reply::Answered {
tool_use,
tool,
ruling,
advanced,
} => json!({ "ok": true, "kind": "answered", "tool_use": tool_use, "tool": tool,
"verdict": ruling.word(), "advanced": advanced }),
Reply::Floored { standing } => {
json!({ "ok": true, "kind": "floored", "standing": standing })
}
Reply::Acked => json!({ "ok": true, "kind": "acked" }),
Reply::TrailCleared => json!({ "ok": true, "kind": "trail-cleared" }),
Reply::Applied { file } => json!({ "ok": true, "kind": "applied", "file": file }),
Reply::Marks { branch, space } => {
json!({ "ok": true, "kind": "marks", "branch": branch,
"space": space.display().to_string() })
}
Reply::Workspaces(rows) => rows_reply("workspaces", rows.iter().map(ws_row)),
Reply::Conversations(rows) => rows_reply("conversations", rows.iter().map(conv_row)),
Reply::Balls(rows) => rows_reply("balls", rows.iter().map(join_row)),
Reply::Board(board) => {
let mut map = rows_map("board", board.rows.iter().map(board_row));
if !board.fleet.is_empty() {
map.insert(
"fleet".to_owned(),
json!(board.fleet.iter().map(fleet_facts).collect::<Vec<Value>>()),
);
}
Value::Object(map)
}
Reply::Attention(rows) => rows_reply("attention", rows.iter().map(queue_row)),
Reply::Ops(rows) => rows_reply("ops", rows.iter().map(op_row)),
Reply::Help(rows) => rows_reply("help", rows.iter().map(help_row)),
Reply::WorkDiff { attempts, patch } => {
crate::workdiff::wire::reply(attempts, patch.as_ref())
}
Reply::Search(found) => json!({
"ok": true, "kind": "search",
"rows": found.hits.iter().map(hit_row).collect::<Vec<Value>>(),
"unreadable": found.unreadable,
}),
Reply::Config { text } => json!({ "ok": true, "kind": "config", "text": text }),
Reply::Providers(rows) => rows_reply("providers", rows.iter().map(provider_row)),
}
}
fn provider_row(row: &crate::config_edit::brazen::ProviderRowView) -> Value {
json!({ "name": row.name, "fact": row.fact, "blocked": row.blocked })
}
pub fn cleared(result: &Result<Reply, String>) -> bool {
match result {
Ok(Reply::Outcome(outcome)) => outcome.ok(),
Ok(_) => true,
Err(_) => false,
}
}
pub fn refusal(error: &str) -> Value {
json!({ "ok": false, "error": error })
}
fn rows_reply(kind: &str, rows: impl Iterator<Item = Value>) -> Value {
Value::Object(rows_map(kind, rows))
}
fn rows_map(kind: &str, rows: impl Iterator<Item = Value>) -> Map<String, Value> {
let mut map = Map::new();
map.insert("ok".to_owned(), json!(true));
map.insert("kind".to_owned(), json!(kind));
map.insert("rows".to_owned(), json!(rows.collect::<Vec<Value>>()));
map
}
fn help_row(row: &crate::boundary::help::HelpRow) -> Value {
json!({ "verb": row.verb, "usage": row.usage,
"summary": row.summary, "detail": row.detail })
}
#[cfg(test)]
mod tests;