mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-15 22:43:28 +08:00
157 lines
4.7 KiB
Rust
157 lines
4.7 KiB
Rust
use anyhow::Result;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::fmt;
|
|
|
|
use crate::session::store::StateStore;
|
|
|
|
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum TaskPriority {
|
|
Low,
|
|
#[default]
|
|
Normal,
|
|
High,
|
|
Critical,
|
|
}
|
|
|
|
impl fmt::Display for TaskPriority {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
let label = match self {
|
|
Self::Low => "low",
|
|
Self::Normal => "normal",
|
|
Self::High => "high",
|
|
Self::Critical => "critical",
|
|
};
|
|
write!(f, "{label}")
|
|
}
|
|
}
|
|
|
|
/// Message types for inter-agent communication.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub enum MessageType {
|
|
/// Task handoff from one agent to another
|
|
TaskHandoff {
|
|
task: String,
|
|
context: String,
|
|
#[serde(default)]
|
|
priority: TaskPriority,
|
|
},
|
|
/// Agent requesting information from another
|
|
Query { question: String },
|
|
/// Response to a query
|
|
Response { answer: String },
|
|
/// Notification of completion
|
|
Completed {
|
|
summary: String,
|
|
files_changed: Vec<String>,
|
|
},
|
|
/// Conflict detected (e.g., two agents editing the same file)
|
|
Conflict { file: String, description: String },
|
|
}
|
|
|
|
/// Send a structured message between sessions.
|
|
pub fn send(db: &StateStore, from: &str, to: &str, msg: &MessageType) -> Result<()> {
|
|
let content = serde_json::to_string(msg)?;
|
|
let msg_type = message_type_name(msg);
|
|
db.send_message(from, to, &content, msg_type)?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn message_type_name(msg: &MessageType) -> &'static str {
|
|
match msg {
|
|
MessageType::TaskHandoff { .. } => "task_handoff",
|
|
MessageType::Query { .. } => "query",
|
|
MessageType::Response { .. } => "response",
|
|
MessageType::Completed { .. } => "completed",
|
|
MessageType::Conflict { .. } => "conflict",
|
|
}
|
|
}
|
|
|
|
pub fn parse(content: &str) -> Option<MessageType> {
|
|
serde_json::from_str(content).ok()
|
|
}
|
|
|
|
pub fn preview(msg_type: &str, content: &str) -> String {
|
|
match parse(content) {
|
|
Some(MessageType::TaskHandoff { task, .. }) => {
|
|
let priority = handoff_priority(content);
|
|
if priority == TaskPriority::Normal {
|
|
format!("handoff {}", truncate(&task, 56))
|
|
} else {
|
|
format!(
|
|
"handoff [{}] {}",
|
|
priority_label(priority),
|
|
truncate(&task, 48)
|
|
)
|
|
}
|
|
}
|
|
Some(MessageType::Query { question }) => {
|
|
format!("query {}", truncate(&question, 56))
|
|
}
|
|
Some(MessageType::Response { answer }) => {
|
|
format!("response {}", truncate(&answer, 56))
|
|
}
|
|
Some(MessageType::Completed {
|
|
summary,
|
|
files_changed,
|
|
}) => {
|
|
if files_changed.is_empty() {
|
|
format!("completed {}", truncate(&summary, 48))
|
|
} else {
|
|
format!(
|
|
"completed {} | {} files",
|
|
truncate(&summary, 40),
|
|
files_changed.len()
|
|
)
|
|
}
|
|
}
|
|
Some(MessageType::Conflict { file, description }) => {
|
|
format!("conflict {} | {}", file, truncate(&description, 40))
|
|
}
|
|
None => format!("{} {}", msg_type.replace('_', " "), truncate(content, 56)),
|
|
}
|
|
}
|
|
|
|
pub fn handoff_priority(content: &str) -> TaskPriority {
|
|
match parse(content) {
|
|
Some(MessageType::TaskHandoff { priority, .. }) => priority,
|
|
_ => extract_legacy_handoff_priority(content),
|
|
}
|
|
}
|
|
|
|
fn extract_legacy_handoff_priority(content: &str) -> TaskPriority {
|
|
let value: serde_json::Value = match serde_json::from_str(content) {
|
|
Ok(value) => value,
|
|
Err(_) => return TaskPriority::Normal,
|
|
};
|
|
match value
|
|
.get("priority")
|
|
.and_then(|priority| priority.as_str())
|
|
.unwrap_or("normal")
|
|
{
|
|
"low" => TaskPriority::Low,
|
|
"high" => TaskPriority::High,
|
|
"critical" => TaskPriority::Critical,
|
|
_ => TaskPriority::Normal,
|
|
}
|
|
}
|
|
|
|
fn priority_label(priority: TaskPriority) -> &'static str {
|
|
match priority {
|
|
TaskPriority::Low => "low",
|
|
TaskPriority::Normal => "normal",
|
|
TaskPriority::High => "high",
|
|
TaskPriority::Critical => "critical",
|
|
}
|
|
}
|
|
|
|
fn truncate(value: &str, max_chars: usize) -> String {
|
|
let trimmed = value.trim();
|
|
if trimmed.chars().count() <= max_chars {
|
|
return trimmed.to_string();
|
|
}
|
|
|
|
let truncated: String = trimmed.chars().take(max_chars.saturating_sub(1)).collect();
|
|
format!("{truncated}…")
|
|
}
|