diff --git a/README.md b/README.md index aaefdf0..ca61a75 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ vamp --review delete 1 3 --repo . # Delete comment 3 from review 1 The review CLI discovers the Git/Jujutsu checkout from `--repo` (default: current directory). It uses the same default configuration, `--config PATH`, `--no-config`, and `review_directory` as the editor, but starts no editor workers or terminal UI. Missing storage lists no reviews without creating a database; incompatible storage is rejected and preserved. +Use the persistent **Review ID** printed by `list`, not a list position. IDs are shared across repositories; listing filters them to the selected checkout, so its first review need not be ID 1. Human-readable listings include a command to show each review. The internal save revision is omitted from text but remains in JSON; it is not a Git/Jujutsu revision. `show all` is not supported: use `show ID --all` to include resolved comments in that review. + `show` includes unresolved comments by default; `--all` includes resolved comments too. Human-readable output is the default. JSON includes the canonical repository root, storage review ID/revision, summary/verdict, total/resolved/unresolved counts, and comments with exact zero-based, end-exclusive grapheme anchors and selected source excerpts—not whole source files. `list --json` returns the repository and review metadata/counts without comments. Explicit editor JSON exports still contain complete anchor source text. `list` and `show` are read-only. `delete REVIEW_ID COMMENT_ID` immediately commits deletion of one resolved or unresolved comment, then prints the updated review with its remaining unresolved comments (`--json` is supported). Both IDs are required; missing reviews/comments and repository mismatches fail without changing stored reviews or creating missing storage. Deleting the last comment keeps the review, summary, and verdict. Concurrent saves use the same revision-conflict protection as the editor; an already-open editor must reload before saving after a CLI deletion. Existing JSON exports are not modified. diff --git a/src/review.rs b/src/review.rs index 2663cdb..f6a5d8e 100644 --- a/src/review.rs +++ b/src/review.rs @@ -172,10 +172,10 @@ impl Review { .filter(|comment| comment.resolved) .count(); format!( - "Review {} (revision {}): {}\n Verdict: {}; {} unresolved, {} resolved ({} total)\n", + "Review ID: {}{}{}\n Verdict: {}; {} unresolved, {} resolved ({} total)\n", self.storage_id .map_or_else(|| "null".into(), |id| id.to_string()), - self.storage_revision, + if self.summary.is_empty() { "" } else { ": " }, self.summary, match self.verdict { Some(Verdict::LooksGood) => "looks_good", @@ -610,7 +610,10 @@ impl Store { let row = rows .next() .map_err(database_error)? - .ok_or("Review does not exist in this repository")?; + .ok_or_else(|| format!( + "Review ID {id} not found in {}.\nRun `vamp --review list` to find review IDs for this repository.", + root.display() + ))?; stored_review(&transaction, row, &root)? }; transaction.commit().map_err(database_error)?; diff --git a/src/review_cli.rs b/src/review_cli.rs index dd12cef..06c7d54 100644 --- a/src/review_cli.rs +++ b/src/review_cli.rs @@ -24,7 +24,11 @@ impl Request { let id = if command == "list" { None } else if command == "show" || command == "delete" { - let error = "show/delete requires a positive review ID"; + let error = if command == "show" { + "`show` requires a positive review ID.\nUsage: vamp --review show ID [--all]\n`--all` includes resolved comments; it does not select all reviews." + } else { + "`delete` requires a positive review ID.\nUsage: vamp --review delete REVIEW_ID COMMENT_ID" + }; let id = args.next().ok_or(error)?; Some( id.to_str() @@ -115,7 +119,10 @@ pub fn run(request: &Request, config: Option<&Path>) -> Result<(), String> { let reviews = if let Some(id) = request.id { let mut review = store .as_ref() - .ok_or("Review does not exist in this repository")? + .ok_or_else(|| format!( + "Review ID {id} not found in {}.\nRun `vamp --review list` to find review IDs for this repository.", + root.display() + ))? .load(&root, id)?; if let Some(comment_id) = request.delete_comment { let index = review @@ -154,8 +161,15 @@ pub fn run(request: &Request, config: Option<&Path>) -> Result<(), String> { if reviews.is_empty() { println!("No stored reviews."); } - for review in reviews { + for review in &reviews { print!("{}", review.summary_text()); + println!( + "\nShow comments: vamp --review show {}", + review.storage_id.unwrap() + ); + } + if !reviews.is_empty() { + println!("Include resolved comments: add --all"); } } Ok(())