use crate::models::field_names;
use anyhow::Result;
use clap::Args;
use serde_json::{Value, json};
use crate::cli::CliOutput;
use crate::config::AppConfig;
use crate::storage as db;
#[derive(Args, Debug, Clone)]
pub struct NotifyArgs {
#[arg(long = "target-agent-id", value_name = "AGENT_ID")]
pub target_agent_id: String,
#[arg(long, value_name = "TEXT")]
pub title: String,
#[arg(long, value_name = "TEXT")]
pub payload: String,
#[arg(long, value_name = "N")]
pub priority: Option<i64>,
#[arg(long, value_name = "TIER")]
pub tier: Option<String>,
#[arg(long)]
pub json: bool,
}
pub fn cmd_notify(
db_path: &std::path::Path,
args: &NotifyArgs,
app_config: &AppConfig,
out: &mut CliOutput<'_>,
) -> Result<()> {
let conn = db::open(db_path)?;
let resolved_ttl = app_config.effective_ttl();
let mut params = json!({
(field_names::TARGET_AGENT_ID): args.target_agent_id,
"title": args.title,
"payload": args.payload,
});
if let Some(p) = args.priority {
params["priority"] = json!(p);
}
if let Some(t) = &args.tier {
params["tier"] = json!(t);
}
let envelope = crate::mcp::handle_notify(&conn, ¶ms, &resolved_ttl, None)
.map_err(|e| anyhow::anyhow!("notify: {e}"))?;
if args.json {
writeln!(out.stdout, "{}", serde_json::to_string(&envelope)?)?;
return Ok(());
}
let id = envelope.get("id").and_then(Value::as_str).unwrap_or("?");
let to = envelope.get("to").and_then(Value::as_str).unwrap_or("?");
writeln!(out.stdout, "notify: id={id} to={to}")?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::test_utils::TestEnv;
#[test]
fn notify_cli_invalid_target_returns_err() {
let mut env = TestEnv::fresh();
let db = env.db_path.clone();
let cfg = AppConfig::default();
let args = NotifyArgs {
target_agent_id: "bad agent with spaces".into(),
title: "subject".into(),
payload: "body".into(),
priority: None,
tier: None,
json: true,
};
let mut out = env.output();
let err = cmd_notify(&db, &args, &cfg, &mut out).expect_err("must fail");
assert!(err.to_string().contains("notify"), "got: {err}");
}
#[test]
fn notify_cli_happy_path_writes_envelope() {
let mut env = TestEnv::fresh();
let db = env.db_path.clone();
let cfg = AppConfig::default();
let args = NotifyArgs {
target_agent_id: "ai:bob".into(),
title: "subject".into(),
payload: "body".into(),
priority: Some(7),
tier: Some("mid".into()),
json: true,
};
{
let mut out = env.output();
cmd_notify(&db, &args, &cfg, &mut out).expect("notify ok");
}
let stdout = env.stdout_str();
let envelope: Value = serde_json::from_str(stdout.trim()).expect("parse envelope");
assert_eq!(envelope["to"].as_str(), Some("ai:bob"));
}
}