Phases 0-1 + Sprint A: module split, CLI layer, org-refresh fix, hygiene
- LICENSE (MIT) + README truth-pass; docs/cli.md CLI contract - CLI subcommands (src/cli_cmds/) per "TUI for users, CLI for users+AI" - Hub/detail refactor: keymap dispatch, modal split, action enum, BgMsg bus - Fix: org repos were never refreshed (owner==username match); refresh now parallel — 49 repos in ~11s, surfaced 70 previously invisible PRs - Fix: 3 date bugs in detail/git.rs (format-local, Local::now, 1y month math) - Stash indicator + [m] actions, session persistence, gh CLI token fallback - Legacy UI modules removed; plan/ docs (roadmap, audit, debate, handoff)
This commit is contained in:
1 parent
5787b14880
commit
0468c032c6
100 files changed
+11614
-9840
No files matched your search
+15
-10
@@ -1,3 +1,10 @@
|
||||
//! User-set display labels for repos (`~/.vulp/labels.toml`), keyed by
|
||||
//! absolute repo path rather than workspace-relative — a repo keeps its
|
||||
//! label even if it's a symlink pulled in from outside the workspace root.
|
||||
//! `workspace_root` is threaded through `load_labels`/`save_label` for a
|
||||
//! consistent call signature with the other per-workspace stores, even
|
||||
//! though labels themselves aren't actually scoped by it.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -8,23 +15,25 @@ struct LabelsFile {
|
||||
labels: HashMap<String, String>, // absolute path → display label
|
||||
}
|
||||
|
||||
fn labels_path(workspace_root: &Path) -> PathBuf {
|
||||
fn labels_path() -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.unwrap_or_else(|| PathBuf::from("~"))
|
||||
.join(".fxg")
|
||||
.join(".vulp")
|
||||
.join("labels.toml")
|
||||
}
|
||||
|
||||
pub fn load_labels(workspace_root: &Path) -> HashMap<PathBuf, String> {
|
||||
let path = labels_path(workspace_root);
|
||||
/// Loads every saved label, keyed by absolute repo path.
|
||||
pub fn load_labels(_workspace_root: &Path) -> HashMap<PathBuf, String> {
|
||||
let path = labels_path();
|
||||
if !path.exists() { return HashMap::new(); }
|
||||
let raw = std::fs::read_to_string(&path).unwrap_or_default();
|
||||
let file: LabelsFile = toml::from_str(&raw).unwrap_or_default();
|
||||
file.labels.into_iter().map(|(k, v)| (PathBuf::from(k), v)).collect()
|
||||
}
|
||||
|
||||
pub fn save_label(repo_path: &Path, label: &str, workspace_root: &Path) -> anyhow::Result<()> {
|
||||
let path = labels_path(workspace_root);
|
||||
/// Sets (or, if `label` is empty, clears) the display label for `repo_path`.
|
||||
pub fn save_label(repo_path: &Path, label: &str, _workspace_root: &Path) -> anyhow::Result<()> {
|
||||
let path = labels_path();
|
||||
let raw = if path.exists() { std::fs::read_to_string(&path)? } else { String::new() };
|
||||
let mut file: LabelsFile = toml::from_str(&raw).unwrap_or_default();
|
||||
|
||||
@@ -39,7 +48,3 @@ pub fn save_label(repo_path: &Path, label: &str, workspace_root: &Path) -> anyho
|
||||
std::fs::write(path, toml::to_string_pretty(&file)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_label(repo_path: &Path, workspace_root: &Path) -> anyhow::Result<()> {
|
||||
save_label(repo_path, "", workspace_root)
|
||||
}
|
||||
Reference in new issue
Block a user