Apply auto-refresh to all commands requiring authentication

Extend automatic OAuth token refresh to all command modules:

Updated commands:
- repo: list, create, clone, info, delete, star, unstar (7 functions)
- issue: list, create, show, edit, comment (5 functions)
- pr: list, create, show, review, merge (5 functions)
- knot: migrate (1 function)

Changes per module:
- Remove SessionManager import (no longer needed)
- Replace SessionManager::load() with util::load_session_with_refresh()
- Handles both pattern variations:
- match mgr.load()? { Some(s) => s, None => ... }
- mgr.load()?.ok_or_else(...)

All authenticated commands now automatically refresh expired tokens
without requiring manual re-authentication, providing a seamless
user experience across the entire CLI.

Changed files
+18 -78
crates
tangled-cli
src
+5 -21
crates/tangled-cli/src/commands/issue.rs
···
};
use anyhow::{anyhow, Result};
use tangled_api::Issue;
-
use tangled_config::session::SessionManager;
pub async fn run(_cli: &Cli, cmd: IssueCommand) -> Result<()> {
match cmd {
···
}
async fn list(args: IssueListArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let pds = session
.pds
.clone()
···
}
async fn create(args: IssueCreateArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let pds = session
.pds
.clone()
···
async fn show(args: IssueShowArgs) -> Result<()> {
// For now, show only accepts at-uri or did:rkey or rkey (for your DID)
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let id = args.id;
let (did, rkey) = parse_record_id(&id, &session.did)?;
let pds = session
···
async fn edit(args: IssueEditArgs) -> Result<()> {
// Simple edit: fetch existing record and putRecord with new title/body
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (did, rkey) = parse_record_id(&args.id, &session.did)?;
let pds = session
.pds
···
}
async fn comment(args: IssueCommentArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (did, rkey) = parse_record_id(&args.id, &session.did)?;
let pds = session
.pds
+1 -5
crates/tangled-cli/src/commands/knot.rs
···
use anyhow::Result;
use git2::{Direction, Repository as GitRepository, StatusOptions};
use std::path::Path;
-
use tangled_config::session::SessionManager;
pub async fn run(_cli: &Cli, cmd: KnotCommand) -> Result<()> {
match cmd {
···
}
async fn migrate(args: KnotMigrateArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
// 1) Ensure we're inside a git repository and working tree is clean
let repo = GitRepository::discover(Path::new("."))?;
let mut status_opts = StatusOptions::new();
+5 -21
crates/tangled-cli/src/commands/pr.rs
···
use anyhow::{anyhow, Result};
use std::path::Path;
use std::process::Command;
-
use tangled_config::session::SessionManager;
pub async fn run(_cli: &Cli, cmd: PrCommand) -> Result<()> {
match cmd {
···
}
async fn list(args: PrListArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let pds = session
.pds
.clone()
···
async fn create(args: PrCreateArgs) -> Result<()> {
// Must be run inside the repo checkout; we will use git format-patch to build the patch
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let pds = session
.pds
.clone()
···
}
async fn show(args: PrShowArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (did, rkey) = parse_record_id(&args.id, &session.did)?;
let pds = session
.pds
···
}
async fn review(args: PrReviewArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (did, rkey) = parse_record_id(&args.id, &session.did)?;
let pds = session
.pds
···
}
async fn merge(args: PrMergeArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (did, rkey) = parse_record_id(&args.id, &session.did)?;
let pds = session
.pds
+7 -31
crates/tangled-cli/src/commands/repo.rs
···
use git2::{build::RepoBuilder, Cred, FetchOptions, RemoteCallbacks};
use serde_json;
use std::path::PathBuf;
-
use tangled_config::session::SessionManager;
use crate::cli::{
Cli, OutputFormat, RepoCloneArgs, RepoCommand, RepoCreateArgs, RepoDeleteArgs, RepoInfoArgs,
···
}
async fn list(cli: &Cli, args: RepoListArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = match mgr.load()? {
-
Some(s) => s,
-
None => return Err(anyhow!("Please login first: tangled auth login")),
-
};
+
let session = crate::util::load_session_with_refresh().await?;
// Use the PDS to list repo records for the user
let pds = session
···
}
async fn create(args: RepoCreateArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = match mgr.load()? {
-
Some(s) => s,
-
None => return Err(anyhow!("Please login first: tangled auth login")),
-
};
+
let session = crate::util::load_session_with_refresh().await?;
let base = std::env::var("TANGLED_API_BASE").unwrap_or_else(|_| "https://tngl.sh".into());
let client = tangled_api::TangledClient::new(base);
···
}
async fn clone(args: RepoCloneArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (owner, name) = parse_repo_ref(&args.repo, &session.handle);
let pds = session
···
}
async fn info(args: RepoInfoArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (owner, name) = parse_repo_ref(&args.repo, &session.handle);
let pds = session
.pds
···
}
async fn delete(args: RepoDeleteArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (owner, name) = parse_repo_ref(&args.repo, &session.handle);
let pds = session
.pds
···
}
async fn star(args: RepoRefArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (owner, name) = parse_repo_ref(&args.repo, &session.handle);
let pds = session
.pds
···
}
async fn unstar(args: RepoRefArgs) -> Result<()> {
-
let mgr = SessionManager::default();
-
let session = mgr
-
.load()?
-
.ok_or_else(|| anyhow!("Please login first: tangled auth login"))?;
+
let session = crate::util::load_session_with_refresh().await?;
let (owner, name) = parse_repo_ref(&args.repo, &session.handle);
let pds = session
.pds