Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 47 additions & 5 deletions src/commands/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,23 +441,65 @@ pub async fn show_comment(client: &HotwiredClient, comment_id: &str) {
}
}

/// Resolve a comment
pub async fn resolve(client: &HotwiredClient, comment_id: &str) {
/// Reply to an existing comment (inherits path/selection from parent)
pub async fn reply_comment(client: &HotwiredClient, comment_id: &str, message: &str) {
let state = validate::require_session(client).await;

match client
.request(
"artifact_resolve_comment",
"artifact_reply_comment",
serde_json::json!({
"runId": state.run_id,
"commentId": comment_id,
"resolvedBy": state.role_id,
"message": message,
"author": state.role_id,
}),
)
.await
{
Ok(response) if response.success => {
println!("Comment resolved: {}", comment_id);
let data = response.data.unwrap_or_default();
let reply_id = data
.get("commentId")
.and_then(|v| v.as_str())
.unwrap_or("?");
println!("Reply added: {} (in thread of {})", reply_id, comment_id);
}
Ok(response) => {
eprintln!(
"error: {}",
response.error.unwrap_or_else(|| "unknown".into())
);
std::process::exit(1);
}
Err(e) => handle_error(e),
}
}

/// Resolve a comment
pub async fn resolve(client: &HotwiredClient, comment_id: &str, reply: Option<&str>) {
let state = validate::require_session(client).await;

let mut params = serde_json::json!({
"runId": state.run_id,
"commentId": comment_id,
"resolvedBy": state.role_id,
});

if let Some(reply_msg) = reply {
params
.as_object_mut()
.unwrap()
.insert("reply".to_string(), serde_json::json!(reply_msg));
}

match client.request("artifact_resolve_comment", params).await {
Ok(response) if response.success => {
if reply.is_some() {
println!("Reply added and comment resolved: {}", comment_id);
} else {
println!("Comment resolved: {}", comment_id);
}
}
Ok(response) => {
eprintln!(
Expand Down
30 changes: 27 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,13 +317,17 @@ enum ArtifactAction {

/// Resolve a comment
///
/// Marks a comment as resolved.
/// Marks a comment as resolved. Optionally leave a closing reply.
///
/// Examples:
/// hotwired-cli artifact resolve cmt_abc123
/// hotwired-cli artifact resolve cmt_abc123 --reply "Addressed in revision 3"
Resolve {
/// Comment ID
comment_id: String,
/// Optional closing reply before resolving
#[arg(long)]
reply: Option<String>,
},

/// List all versions of an artifact
Expand Down Expand Up @@ -378,6 +382,20 @@ enum CommentAction {
reply_to: Option<String>,
},

/// Reply to an existing comment
///
/// Creates a threaded reply inheriting the parent's path and selection.
/// No need to specify path or target_text — they are inherited from the parent.
///
/// Examples:
/// hotwired-cli artifact comment reply cmt_abc123 "I agree, will fix"
Reply {
/// Comment ID to reply to
comment_id: String,
/// Reply message
message: String,
},

/// Show a specific comment and its thread
///
/// Retrieves a comment by ID along with any replies in its thread.
Expand Down Expand Up @@ -648,6 +666,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
)
.await;
}
CommentAction::Reply {
comment_id,
message,
} => {
commands::artifact::reply_comment(&client, &comment_id, &message).await;
}
CommentAction::Show { comment_id } => {
commands::artifact::show_comment(&client, &comment_id).await;
}
Expand All @@ -658,8 +682,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
ArtifactAction::Comments { path, status } => {
commands::artifact::list_comments(&client, &path, &status).await;
}
ArtifactAction::Resolve { comment_id } => {
commands::artifact::resolve(&client, &comment_id).await;
ArtifactAction::Resolve { comment_id, reply } => {
commands::artifact::resolve(&client, &comment_id, reply.as_deref()).await;
}
ArtifactAction::Versions { path } => {
commands::artifact::list_versions(&client, &path).await;
Expand Down