feat(cli/org): org edit — flag-driven field update for login/note/identity

This commit is contained in:
adlee-was-taken
2026-06-20 14:12:46 -04:00
parent 2acd57a4a5
commit 057a7defe5
3 changed files with 122 additions and 4 deletions

View File

@@ -973,6 +973,77 @@ fn resolve_org_query<'a>(
}
}
pub fn run_edit(
dir: &Path,
query: &str,
title: Option<String>,
username: Option<String>,
url: Option<String>,
password: Option<String>,
body: Option<String>,
email: Option<String>,
phone: Option<String>,
full_name: Option<String>,
) -> Result<()> {
use relicario_core::time::now_unix;
use relicario_core::ItemCore;
use zeroize::Zeroizing;
let vault = crate::org_session::open_org_vault(Some(dir))?;
let caller = vault.current_member()?;
let manifest = vault.load_manifest()?;
let visible = manifest.filter_for_member(&caller);
let entry = resolve_org_query(&visible, query)?;
let collection = entry.collection.clone();
let id = entry.id.clone();
crate::org_session::UnlockedOrgVault::ensure_grant(&caller, &collection)?;
let mut item = vault.load_item(&collection, &id)?;
if let Some(t) = title { item.title = t; }
match &mut item.core {
ItemCore::Login(l) => {
if let Some(u) = username { l.username = Some(u); }
if let Some(u) = url {
l.url = Some(url::Url::parse(&u).with_context(|| format!("invalid URL: {u}"))?);
}
if let Some(p) = password { l.password = Some(Zeroizing::new(p)); }
}
ItemCore::SecureNote(n) => {
if let Some(b) = body { n.body = Zeroizing::new(b); }
}
ItemCore::Identity(i) => {
if let Some(v) = full_name { i.full_name = Some(v); }
if let Some(v) = email { i.email = Some(v); }
if let Some(v) = phone { i.phone = Some(v); }
}
_ => anyhow::bail!("org edit currently supports login, secure-note, and identity items"),
}
item.modified = now_unix();
let item_rel = vault.save_item(&collection, &item)?;
let mut manifest = vault.load_manifest()?;
upsert_org_entry(&mut manifest, &item, &collection);
vault.save_manifest(&manifest)?;
let subject = format!(
"org edit: {} ({})",
crate::helpers::sanitize_for_commit(&item.title),
item.id.as_str()
);
let commit_msg = format!(
"{subject}\n\nRelicario-Actor: {} {}\nRelicario-Action: item-update\nRelicario-Collection: {}\nRelicario-Item: {}",
caller.display_name, caller.member_id.as_str(), collection, item.id.as_str()
);
crate::org_session::org_git_run(&vault.root, &["add", &item_rel, "manifest.enc"], "org edit: git add")?;
crate::org_session::org_git_run(&vault.root, &["commit", "-m", &commit_msg], "org edit: git commit")?;
println!("Updated {}", item.id.as_str());
Ok(())
}
/// Insert-or-replace an `OrgManifestEntry` mirroring the personal-vault
/// `Manifest::upsert`. Keyed by item id.
fn upsert_org_entry(