use serde::{Deserialize, Serialize};
use crate::bash_background::BgTaskStatus;
pub const ERROR_PERMISSION_REQUIRED: &str = "permission_required";
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ProgressKind {
Stdout,
Stderr,
}
#[derive(Debug, Clone, Serialize)]
pub struct ProgressFrame {
#[serde(rename = "type")]
pub frame_type: &'static str,
pub request_id: String,
pub kind: ProgressKind,
pub chunk: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct PermissionAskFrame {
#[serde(rename = "type")]
pub frame_type: &'static str,
pub request_id: String,
pub asks: serde_json::Value,
}
#[derive(Debug, Clone, Serialize)]
pub struct BashCompletedFrame {
#[serde(rename = "type")]
pub frame_type: &'static str,
pub task_id: String,
pub session_id: String,
pub status: BgTaskStatus,
pub exit_code: Option<i32>,
pub command: String,
#[serde(default)]
pub output_preview: String,
#[serde(default)]
pub output_truncated: bool,
}
#[derive(Debug, Clone, Serialize)]
#[serde(untagged)]
pub enum PushFrame {
Progress(ProgressFrame),
BashCompleted(BashCompletedFrame),
}
impl PermissionAskFrame {
pub fn new(request_id: impl Into<String>, asks: serde_json::Value) -> Self {
Self {
frame_type: "permission_ask",
request_id: request_id.into(),
asks,
}
}
}
impl ProgressFrame {
pub fn new(
request_id: impl Into<String>,
kind: ProgressKind,
chunk: impl Into<String>,
) -> Self {
Self {
frame_type: "progress",
request_id: request_id.into(),
kind,
chunk: chunk.into(),
}
}
}
impl BashCompletedFrame {
pub fn new(
task_id: impl Into<String>,
session_id: impl Into<String>,
status: BgTaskStatus,
exit_code: Option<i32>,
command: impl Into<String>,
output_preview: impl Into<String>,
output_truncated: bool,
) -> Self {
Self {
frame_type: "bash_completed",
task_id: task_id.into(),
session_id: session_id.into(),
status,
exit_code,
command: command.into(),
output_preview: output_preview.into(),
output_truncated,
}
}
}
pub const DEFAULT_SESSION_ID: &str = "__default__";
#[derive(Debug, Deserialize)]
pub struct RawRequest {
pub id: String,
#[serde(alias = "method")]
pub command: String,
#[serde(default)]
pub lsp_hints: Option<serde_json::Value>,
#[serde(default)]
pub session_id: Option<String>,
#[serde(flatten)]
pub params: serde_json::Value,
}
impl RawRequest {
pub fn session(&self) -> &str {
self.session_id.as_deref().unwrap_or(DEFAULT_SESSION_ID)
}
}
#[derive(Debug, Serialize)]
pub struct Response {
pub id: String,
pub success: bool,
#[serde(flatten)]
pub data: serde_json::Value,
}
#[derive(Debug, Deserialize)]
pub struct EchoParams {
pub message: String,
}
impl Response {
pub fn success(id: impl Into<String>, data: serde_json::Value) -> Self {
Response {
id: id.into(),
success: true,
data,
}
}
pub fn error(id: impl Into<String>, code: &str, message: impl Into<String>) -> Self {
Response {
id: id.into(),
success: false,
data: serde_json::json!({
"code": code,
"message": message.into(),
}),
}
}
pub fn error_with_data(
id: impl Into<String>,
code: &str,
message: impl Into<String>,
extra: serde_json::Value,
) -> Self {
let mut data = serde_json::json!({
"code": code,
"message": message.into(),
});
if let (Some(base), Some(ext)) = (data.as_object_mut(), extra.as_object()) {
for (k, v) in ext {
base.insert(k.clone(), v.clone());
}
}
Response {
id: id.into(),
success: false,
data,
}
}
}