Colony CLI: inbox + ack commands

- colony inbox [--json] — show unacked inbox items
- colony ack <id> [--all] [--quiet] — ack items
- Client methods: get_inbox(), ack_inbox()
- AckRequest gets Serialize derive for CLI use

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 22:44:21 +02:00
parent 2127bf4ef0
commit 321adfb9e9
3 changed files with 71 additions and 1 deletions

View File

@@ -79,6 +79,24 @@ impl ColonyClient {
res.json().await.unwrap()
}
pub async fn get_inbox(&self) -> Vec<InboxItem> {
let res = self.http
.get(self.url(&format!("/api/inbox?{}", self.config.user_query())))
.send().await.unwrap_or_else(|e| { eprintln!("colony unreachable: {e}"); process::exit(1); });
if !res.status().is_success() { self.handle_error(res).await; }
res.json().await.unwrap()
}
pub async fn ack_inbox(&self, ids: &[i64]) -> serde_json::Value {
let body = AckRequest { ids: ids.to_vec() };
let res = self.http
.post(self.url("/api/inbox/ack"))
.json(&body)
.send().await.unwrap_or_else(|e| { eprintln!("colony unreachable: {e}"); process::exit(1); });
if !res.status().is_success() { self.handle_error(res).await; }
res.json().await.unwrap()
}
/// Resolve channel name to ID. Fetches channel list and finds by name.
pub async fn resolve_channel(&self, name: &str) -> String {
let channels = self.get_channels().await;

View File

@@ -56,6 +56,21 @@ enum Commands {
#[arg(long)]
json: bool,
},
/// Check inbox (unacked mentions + activity)
Inbox {
#[arg(long)]
json: bool,
},
/// Acknowledge inbox items
Ack {
/// Inbox item IDs to ack
ids: Vec<i64>,
/// Ack all unacked items
#[arg(long)]
all: bool,
#[arg(long)]
quiet: bool,
},
/// Initialize .colony.toml
Init {
#[arg(long)]
@@ -172,6 +187,43 @@ async fn run_command(cmd: Commands, client: &ColonyClient) {
}
}
Commands::Inbox { json } => {
let items = client.get_inbox().await;
if json {
println!("{}", serde_json::to_string(&items).unwrap());
} else if items.is_empty() {
println!("inbox empty");
} else {
for item in &items {
println!("[{}] #{} [{}] {}: {} ({})",
item.id,
item.channel_name,
item.message.seq,
item.message.user.username,
item.message.content,
item.trigger,
);
}
}
}
Commands::Ack { ids, all, quiet } => {
let to_ack = if all {
let items = client.get_inbox().await;
items.iter().map(|i| i.id).collect::<Vec<_>>()
} else {
ids
};
if to_ack.is_empty() {
if !quiet { println!("nothing to ack"); }
} else {
let result = client.ack_inbox(&to_ack).await;
if !quiet {
println!("acked {} items", result["acked"]);
}
}
}
Commands::Init { .. } => unreachable!(),
}
}

View File

@@ -114,7 +114,7 @@ pub struct InboxQuery {
pub user: String,
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Serialize, Deserialize)]
pub struct AckRequest {
pub ids: Vec<i64>,
}