Files
vulp/docs/cross-platform.md
dualfroz 0468c032c6 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)
2026-07-06 14:42:52 +02:00

8.6 KiB
Raw Permalink Blame History

vulp — strategia cross-platform

Cel: jedna binarka, trzy systemy, instalacja w 30 sekund, zero wiedzy technicznej wymaganej.


Stan obecny

Rust kompiluje się do natywnych binarek bez zewnętrznych zależności runtime. To dobra podstawa — nie trzeba instalować Pythona, Node.js ani JVM. Ale dziś jedynym sposobem instalacji jest cargo install --path ., co wymaga zainstalowanego Rusta i środowiska build. Dla grafika — nierealne.

Obecny problem z keyring: na Linuksie wymaga libdbus lub libsecret. Do rozwiązania przy pakowaniu.


Cel UX instalacji

Windows: Pobierasz plik .exe. Klikasz go dwukrotnie. Otwiera się terminal z konfiguratorem. Po 2 minutach piszesz vulp status i to działa.

Linux: Wklejasz jedną linię w terminal. Po 10 sekundach piszesz vulp status i to działa.

macOS: brew install. Jedna komenda.


Strategia dystrybucji — GitHub Releases + CI

GitHub Actions — automatyczne buildowanie binarek

Przy każdym tagu (v*.*.*) CI buduje binarkę na 4 targety:

# .github/workflows/release.yml
strategy:
  matrix:
    include:
      - os: ubuntu-latest
        target: x86_64-unknown-linux-musl   # statyczna binarka — działa na każdym Linuksie
        artifact: vulp-linux-x64
      - os: ubuntu-latest
        target: aarch64-unknown-linux-musl  # ARM (np. Raspberry Pi, nowe serwery)
        artifact: vulp-linux-arm64
      - os: windows-latest
        target: x86_64-pc-windows-msvc
        artifact: vulp-windows-x64.exe
      - os: macos-latest
        target: x86_64-apple-darwin
        artifact: vulp-macos-x64
      - os: macos-latest
        target: aarch64-apple-darwin         # Apple Silicon (M1/M2/M3)
        artifact: vulp-macos-arm64

Używamy x86_64-unknown-linux-musl zamiast gnu — binarka statyczna, nie wymaga żadnych systemowych .so. Keyring na Linuksie fallback do pliku szyfrowanego (jeśli brak dbus).

Pliki lądują w GitHub Releases jako Assets. Użytkownik pobiera odpowiedni plik dla swojego systemu.


Linux — instalacja

Skrypt jednolinijkowy (docelowy UX)

curl -fsSL https://github.com/twoj-user/vulp/releases/latest/download/install.sh | bash

Skrypt robi:

  1. Wykrywa architekturę (uname -m)
  2. Pobiera odpowiednią binarkę z GitHub Releases
  3. Umieszcza ją w ~/.local/bin/vulp
  4. Dodaje ~/.local/bin do $PATH w .bashrc/.zshrc jeśli jeszcze nie ma
  5. Jeśli brak konfiguracji → uruchamia vulp setup (first-run wizard)
#!/bin/bash
set -e
ARCH=$(uname -m)
OS=linux
case $ARCH in
  x86_64)  FILE="vulp-linux-x64" ;;
  aarch64) FILE="vulp-linux-arm64" ;;
  *) echo "Nieobsługiwana architektura: $ARCH"; exit 1 ;;
esac

LATEST=$(curl -s https://api.github.com/repos/twoj-user/vulp/releases/latest | grep tag_name | cut -d '"' -f 4)
URL="https://github.com/twoj-user/vulp/releases/download/${LATEST}/${FILE}"

mkdir -p ~/.local/bin
curl -fsSL "$URL" -o ~/.local/bin/vulp
chmod +x ~/.local/bin/vulp

# Dodaj do PATH jeśli brak
if ! echo "$PATH" | grep -q "$HOME/.local/bin"; then
  echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
  export PATH="$HOME/.local/bin:$PATH"
fi

echo "vulp zainstalowany. Uruchamianie konfiguracji..."
vulp setup

Opcjonalnie: pakiety .deb i .rpm

Generowane przez cargo-deb i cargo-rpm w CI — przydatne dla systemów zarządzanych przez IT.

# Ubuntu/Debian
sudo dpkg -i vulp_0.1.0_amd64.deb

# Fedora/RHEL/CentOS
sudo rpm -i vulp-0.1.0.x86_64.rpm

Windows — instalacja

Opcja A: Kliknięcie .exe (docelowy UX dla grafika)

Gdy użytkownik dwukrotnie kliknie vulp-windows-x64.exe bez żadnych argumentów i brak konfiguracji, zamiast wyświetlić help i zamknąć okno — otwiera PowerShell z konfiguratorem.

Implementacja w src/main.rs:

#[cfg(windows)]
fn ensure_console() {
    // Jeśli uruchomiono przez dwuklik (nie z terminala), otwórz nowe okno konsoli
    // i uruchom vulp setup w nim
    use std::os::windows::process::CommandExt;
    if !is_launched_from_terminal() {
        std::process::Command::new("cmd")
            .args(["/k", "vulp.exe", "setup"])
            .creation_flags(0x00000010) // CREATE_NEW_CONSOLE
            .spawn().ok();
        std::process::exit(0);
    }
}

Opcja B: Skrypt PowerShell (instalacja systemowa)

# Wklej w PowerShell jako Administrator:
iwr https://github.com/twoj-user/vulp/releases/latest/download/install.ps1 | iex

Skrypt:

  1. Pobiera vulp-windows-x64.exe
  2. Umieszcza w %USERPROFILE%\AppData\Local\vulp\
  3. Dodaje ten folder do $PATH (przez [Environment]::SetEnvironmentVariable)
  4. Uruchamia vulp setup w nowym oknie terminalu

Opcja C: WinGet (Microsoft Store CLI) — przyszłość

winget install vulp

Wymaga zgłoszenia pakietu do repozytorium winget-pkgs.


macOS — instalacja

Homebrew (docelowy UX)

brew install twoj-user/tap/vulp

Wymaga stworzenia własnego "tap" (repozytorium z formularzem Homebrew):

# Formula/vulp.rb
class Vulp < Formula
  desc "Multi-repository git workflow manager"
  homepage "https://github.com/twoj-user/vulp"
  version "0.1.0"

  on_macos do
    if Hardware::CPU.arm?
      url "https://github.com/twoj-user/vulp/releases/download/v0.1.0/vulp-macos-arm64"
      sha256 "..."
    else
      url "https://github.com/twoj-user/vulp/releases/download/v0.1.0/vulp-macos-x64"
      sha256 "..."
    end
  end

  def install
    bin.install "vulp-macos-arm64" => "vulp"
  end
end

First-run wizard

Kluczowy element UX. Gdy użytkownik uruchamia dowolną komendę po raz pierwszy (brak ~/.vulp/config.toml), zamiast error'a dostaje automatyczny setup.

Implementacja w src/app.rs, przed każdym match cli.command:

// src/app.rs
pub async fn run(cli: Cli) -> Result<()> {
    // Jeśli brak konfiguracji → uruchom first-run setup
    if !config::config_path().exists() {
        println!("Wygląda na to, że uruchamiasz vulp po raz pierwszy.");
        println!("Przeprowadźmy krótką konfigurację (zajmie ~2 minuty).\n");
        first_run_setup().await?;
    }

    let cfg = config::load_config()?;
    // ... reszta
}

async fn first_run_setup() -> Result<()> {
    // 1. Uruchom config TUI
    let cfg = config::run_first_time().await?;
    // 2. Zapytaj o dodanie konta
    if inquire::Confirm::new("Czy chcesz teraz podłączyć konto GitHub/GitLab?")
        .with_default(true).prompt()? {
        // Uruchom auth add wizard
        auth::run_add_wizard(&cfg).await?;
    }
    println!("\nGotowe! Wpisz 'vulp status' żeby zobaczyć swoje projekty.");
    Ok(())
}

Systemowe zależności — problemy i rozwiązania

Zależność Problem Rozwiązanie
libgit2 Wymagana na Linuksie przy dynamicznym linkowaniu Używamy git2 z feature vendored — kompiluje libgit2 statycznie
keyring / libsecret Wymaga dbus na Linuksie headless Fallback do zaszyfrowanego pliku ~/.vulp/credentials.enc gdy brak dbus
openssl Różne wersje na różnych systemach Feature native-tls → rustls — TLS w całości wbudowany w Rust
# Cargo.toml — docelowa konfiguracja dla statycznych binarek
[dependencies]
git2     = { version = "0.19", features = ["vendored"] }
reqwest  = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }
keyring  = { version = "3", features = ["sync-secret-service"] }

O nazwie

Aktualna nazwa vulp ("finally executable git") to placeholder — dobra jako codename, ale przed publicznym wydaniem warto rozważyć zmianę.

Kryteria dobrej nazwy narzędzia CLI:

  • Krótka (2–4 znaki idealne, max 6)
  • Łatwa do wymówienia i zapamiętania
  • Nie koliduje z istniejącymi komendami systemowymi
  • Nawiązuje do funkcji (opcjonalnie)

Kilka luźnych kierunków (bez rekomendacji — ostateczna decyzja należy do Ciebie):

  • Coś od "workspace" / "repos" / "git"
  • Coś sugerującego "wielość" lub "hub"
  • Akronim który znaczy coś po polsku, a po angielsku brzmi jak komenda

Niezależnie od wyboru nazwy — warto go podjąć przed stworzeniem Homebrew tap i pierwszym publicznym Release, bo zmiana nazwy binarki po publikacji jest uciążliwa.


Roadmap dystrybucji

v0.1 (teraz)    cargo install — tylko dla developerów
v0.2            GitHub Releases z binaries (Linux + Windows + macOS)
                Skrypt instalacyjny curl | bash
v0.3            First-run wizard (bez potrzeby wpisywania komend setup)
                PowerShell install script dla Windows
v0.4            Homebrew tap dla macOS
v1.0            Stabilny API, binarka klikalna na Windows
                WinGet (opcjonalnie)
                Pakiety .deb/.rpm (opcjonalnie)