feat: improve how the issue command handles issue #6

open
opened by dunkirk.sh targeting main

This patch fixes tangled-cli issue list to properly deserialize issue records by making optional fields (createdAt, $type, owner, issueId) optional in the Issue struct, adds a --state filter to show only open or closed issues by querying issue state records and filtering client-side, and formats repository display as readable "handle/name" (e.g., "dunkirk.sh/thistle") instead of AT-URIs while using a cache to avoid repeated API calls for the same repository.

Changed files
+39 -2
crates
tangled-api
+2 -2
crates/tangled-api/src/lib.rs
··· 2 3 pub use client::TangledClient; 4 pub use client::{ 5 - CreateRepoOptions, DefaultBranch, Issue, IssueRecord, Language, Languages, Pull, PullRecord, 6 - RepoRecord, Repository, Secret, 7 };
··· 2 3 pub use client::TangledClient; 4 pub use client::{ 5 + CreateRepoOptions, DefaultBranch, Issue, IssueRecord, IssueState, Language, Languages, Pull, 6 + PullRecord, RepoRecord, Repository, Secret, 7 };
+37
crates/tangled-api/src/client.rs
··· 415 Err(anyhow!("repo not found for owner/name")) 416 } 417 418 pub async fn delete_repo( 419 &self, 420 did: &str,
··· 415 Err(anyhow!("repo not found for owner/name")) 416 } 417 418 + pub async fn get_repo_by_rkey( 419 + &self, 420 + did: &str, 421 + rkey: &str, 422 + bearer: Option<&str>, 423 + ) -> Result<Repository> { 424 + #[derive(Deserialize)] 425 + struct GetRes { 426 + value: Repository, 427 + } 428 + let params = [ 429 + ("repo", did.to_string()), 430 + ("collection", "sh.tangled.repo".to_string()), 431 + ("rkey", rkey.to_string()), 432 + ]; 433 + let res: GetRes = self 434 + .get_json("com.atproto.repo.getRecord", &params, bearer) 435 + .await?; 436 + Ok(res.value) 437 + } 438 + 439 + pub async fn resolve_did_to_handle( 440 + &self, 441 + did: &str, 442 + bearer: Option<&str>, 443 + ) -> Result<String> { 444 + #[derive(Deserialize)] 445 + struct Res { 446 + handle: String, 447 + } 448 + let params = [("repo", did.to_string())]; 449 + let res: Res = self 450 + .get_json("com.atproto.repo.describeRepo", &params, bearer) 451 + .await?; 452 + Ok(res.handle) 453 + } 454 + 455 pub async fn delete_repo( 456 &self, 457 did: &str,