### Tether CLI Installation Methods Source: https://github.com/paddo-tech/tether-cli/blob/main/SPEC.md Bash commands for installing the Tether CLI using various methods, including Homebrew, direct download script, Cargo, and building from source. ```bash # Homebrew (recommended) brew install tether-cli # Direct download curl -fsSL https://tether-cli.com/install.sh | bash # Cargo (for Rust users) cargo install tether-cli # Build from source git clone https://github.com/paddo-tech/tether-cli cd tether-cli cargo build --release ``` -------------------------------- ### Start Development Server with Bun Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md Command to start the local development server for the Tether CLI website using Bun. This enables hot reloading for quick iteration during development. ```bash bun run dev ``` -------------------------------- ### Tether CLI Configuration File Example Source: https://github.com/paddo-tech/tether-cli/blob/main/SPEC.md Example of the TOML configuration file for Tether CLI, located at ~/.tether/config.toml. It specifies sync intervals, strategies, backend settings, and package manager configurations. ```toml [sync] interval = "5m" strategy = "last-write-wins" [backend] type = "git" url = "git@github.com:username/tether-sync.git" [packages.brew] enabled = true sync_casks = true sync_taps = true [packages.npm] enabled = true sync_versions = false # false = install latest, true = exact versions [packages.pnpm] enabled = true sync_versions = false [dotfiles] files = [".zshrc", ".zprofile", ".gitconfig"] ``` -------------------------------- ### Clone and Install Dependencies with Bun Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md Instructions for cloning the Tether CLI website repository and installing its dependencies using the Bun package manager. This is a prerequisite for local development. ```bash git clone https://github.com/paddo-tech/tether-cli-website.git cd tether-cli-website bun install ``` -------------------------------- ### Install Tether CLI via Homebrew Source: https://github.com/paddo-tech/tether-cli/blob/main/AGENTS.md Instructions for users to install the Tether CLI using the Homebrew package manager. This involves tapping the custom Homebrew repository and then installing the 'tether' formula. This is the recommended method for end-users. ```bash brew tap paddo-tech/tap brew install tether ``` -------------------------------- ### Install Fly CLI for Deployment Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md Shell command to download and install the Fly.io CLI tool, which is necessary for deploying the Tether CLI website to Fly.io. ```bash curl -L https://fly.io/install.sh | sh ``` -------------------------------- ### Tether CLI State File Example Source: https://github.com/paddo-tech/tether-cli/blob/main/SPEC.md Example of the JSON state file for Tether CLI, located at ~/.tether/state.json. It tracks machine ID, last sync time, file hashes, modification times, sync status, and package manager sync information. ```json { "machine_id": "macbook-pro-2021", "last_sync": "2025-01-15T10:30:00Z", "files": { ".zshrc": { "hash": "a3f5e1b2c...", "last_modified": "2025-01-15T10:25:00Z", "synced": true }, ".gitconfig": { "hash": "d4e6f2c3a...", "last_modified": "2025-01-14T15:20:00Z", "synced": true } }, "packages": { "brew": { "last_sync": "2025-01-15T10:30:00Z", "hash": "b5c7d3e1f..." }, "npm": { "last_sync": "2025-01-15T10:30:00Z", "hash": "c6d8e4f2a..." } } } ``` -------------------------------- ### Initialize Tether CLI Configuration Source: https://context7.com/paddo-tech/tether-cli/llms.txt Sets up the Tether CLI on a new machine. This involves creating the necessary directory structure, configuring the Git repository for synchronization, setting up encryption using a user-provided passphrase, and performing an initial synchronization. It handles both automatic and manual repository setup and saves the configuration to '~/.tether/config.toml'. ```rust use tether::cli::{Output, Prompt}; use tether::config::Config; use tether::sync::{GitBackend, SyncEngine}; pub async fn run(repo: Option<&str>, no_daemon: bool) -> Result<()><{ // Create .tether directory structure let tether_dir = Config::config_dir()?; std::fs::create_dir_all(&tether_dir)?; // Setup GitHub repo (automatic or manual) let repo_url = if let Some(url) = repo { url.to_string() } else { // Interactive repo selection setup_repository().await? }; // Clone sync repository let sync_path = SyncEngine::sync_path()?; GitBackend::clone(&repo_url, &sync_path)?; // Setup encryption let passphrase = Prompt::password("Passphrase")?; let key = crate::security::encryption::generate_key(); crate::security::store_encryption_key_with_passphrase(&key, &passphrase)?; // Save configuration let mut config = Config::default(); config.backend.url = repo_url; config.save()?; // Initial sync super::sync::run(false, false).await?; Ok(()) } ``` -------------------------------- ### Deploy to Fly.io Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md Command to deploy the Tether CLI website to Fly.io. This command assumes the Fly CLI is installed and the user is authenticated. ```bash fly deploy ``` -------------------------------- ### Rust npm Package Manager Implementation Source: https://context7.com/paddo-tech/tether-cli/llms.txt Implements the PackageManager trait for npm, allowing synchronization of globally installed npm packages. It exports a list of package names and imports them using `npm install -g`. This implementation uses the `npm list -g --depth=0 --json` command for exporting and iterates through lines for importing. ```rust // src/packages/npm.rs pub struct NpmManager; #[async_trait] impl PackageManager for NpmManager { async fn export_manifest(&self) -> Result { let output = Command::new("npm") .args(["list", "-g", "--depth=0", "--json"]) .output() .await?; let json: serde_json::Value = serde_json::from_slice(&output.stdout)?; let packages = json["dependencies"].as_object().unwrap(); // Export as simple list (one per line) let manifest = packages .keys() .map(|name| name.as_str()) .collect::>() .join("\n"); Ok(manifest) } async fn import_manifest(&self, manifest_content: &str) -> Result<()> { for line in manifest_content.lines() { let package = line.trim(); if !package.is_empty() { Command::new("npm") .args(["install", "-g", package]) .status() .await?; } } Ok(()) } } // Example usage: let npm = NpmManager::new(); // Machine A: Export installed packages let manifest = npm.export_manifest().await?; // Content: // typescript // eslint // prettier // vercel std::fs::write(sync_path.join("manifests/npm.txt"), manifest)?; // Machine B: Import packages let manifest = std::fs::read_to_string(sync_path.join("manifests/npm.txt"))?; npm.import_manifest(&manifest).await?; // Installs: typescript, eslint, prettier, vercel globally ``` -------------------------------- ### Tether CLI Homebrew Formula Source: https://github.com/paddo-tech/tether-cli/blob/main/SPEC.md Ruby code for the Homebrew formula used to distribute the Tether CLI. It defines the formula's metadata, dependencies, build process, and installation steps. ```ruby # Formula: tether-cli.rb class TetherCli < Formula desc "Sync development environment across multiple Macs" homepage "https://tether-cli.com" url "https://github.com/paddo-tech/tether-cli/archive/v1.0.0.tar.gz" sha256 "..." license "MIT" depends_on :macos def install system "cargo", "build", "--release" bin.install "target/release/tether" end def post_install puts "Run 'tether init' to get started!" end end ``` -------------------------------- ### Build and Preview Production Site with Bun Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md Commands to build the Tether CLI website for production and preview the built site locally using Bun. This is useful for testing the production build before deployment. ```bash bun run build bun run preview ``` -------------------------------- ### Build, Run, Test, and Lint Rust Code with Cargo Source: https://github.com/paddo-tech/tether-cli/blob/main/AGENTS.md This snippet demonstrates common Cargo commands for managing Rust projects. It includes building the project, running it in development mode, executing tests, linting with Clippy, and formatting code. Linting with Clippy is a mandatory step before committing changes. ```bash cargo build # Build cargo run -- # Run in dev cargo test # Test cargo clippy -- -D warnings # Lint (must pass before commits) cargo fmt # Format ``` -------------------------------- ### Rust PackageManager Trait Source: https://context7.com/paddo-tech/tether-cli/llms.txt Defines a generic trait for package managers, enabling unified operations like listing, installing, and exporting manifests. It includes default implementations for some methods and is designed to be implemented by specific package managers like Homebrew and npm. Requires `async-trait` and `serde` crates. ```rust // src/packages/manager.rs use async_trait::async_trait; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PackageInfo { pub name: String, pub version: Option, } #[async_trait] pub trait PackageManager: Send + Sync { /// List all installed packages async fn list_installed(&self) -> Result>; /// Install a specific package async fn install(&self, package: &PackageInfo) -> Result<()>; /// Check if package manager is available async fn is_available(&self) -> bool; /// Get package manager name fn name(&self) -> &str; /// Export packages to manifest (native format) async fn export_manifest(&self) -> Result; /// Import packages from manifest async fn import_manifest(&self, manifest_content: &str) -> Result<()>; /// Remove unlisted packages async fn remove_unlisted(&self, manifest_content: &str) -> Result<()>; /// Update all packages async fn update_all(&self) -> Result<()>; /// Compute manifest hash for change detection async fn compute_manifest_hash(&self) -> Result { let manifest = self.export_manifest().await?; Ok(format!("{:x}", Sha256::digest(manifest.as_bytes()))) } } // Example: Homebrew implementation pub struct BrewManager; #[async_trait] impl PackageManager for BrewManager { async fn export_manifest(&self) -> Result { // Generates Brewfile format let output = Command::new("brew") .args(["bundle", "dump", "--file=/dev/stdout"]) .output() .await?; Ok(String::from_utf8(output.stdout)?) } async fn import_manifest(&self, manifest_content: &str) -> Result<()> { // Write Brewfile and install std::fs::write("/tmp/Brewfile", manifest_content)?; Command::new("brew") .args(["bundle", "install", "--file=/tmp/Brewfile"]) .status() .await?; Ok(()) } async fn update_all(&self) -> Result<()> { Command::new("brew").arg("upgrade").status().await?; Ok(()) } fn name(&self) -> &str { "brew" } } // Example usage - sync packages across machines: let config = Config::load()?; let sync_path = SyncEngine::sync_path()?; // Export packages on Machine A if config.packages.brew.enabled { let brew = BrewManager::new(); if brew.is_available().await { let manifest = brew.export_manifest().await?; // Brewfile format: // tap "homebrew/bundle" // brew "git" // brew "ripgrep" // cask "visual-studio-code" std::fs::write(sync_path.join("manifests/Brewfile"), manifest)?; } } // Import packages on Machine B let brewfile = std::fs::read_to_string(sync_path.join("manifests/Brewfile"))?; brew.import_manifest(&brewfile).await?; // Installs: git, ripgrep, visual-studio-code ``` -------------------------------- ### Set Up Custom Domains on Fly.io Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md Commands to add custom SSL certificates for tether-cli.com and www.tether-cli.com to the Fly.io application. This is an optional step for custom domain configuration. ```bash fly certs add tether-cli.com fly certs add www.tether-cli.com ``` -------------------------------- ### Astro Layout for Documentation Pages Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md Astro component code for creating new documentation pages. It imports `DocsLayout` and includes a basic structure for a page title and content. New pages should be created in `src/pages/docs/` and the sidebar navigation in `src/layouts/DocsLayout.astro` should be updated. ```astro --- import DocsLayout from '../../layouts/DocsLayout.astro'; ---

Page Content

``` -------------------------------- ### Load and Save Tether Configuration (Rust) Source: https://context7.com/paddo-tech/tether-cli/llms.txt Demonstrates loading a Tether configuration from a TOML file and saving modified configurations. It handles file reading, TOML parsing, and atomic writing to ensure data integrity. Requires the `serde` and `toml` crates. ```rust use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { pub sync: SyncConfig, pub backend: BackendConfig, pub packages: PackagesConfig, pub dotfiles: DotfilesConfig, pub security: SecurityConfig, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DotfilesConfig { pub files: Vec, pub dirs: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum DotfileEntry { Simple(String), WithOptions { path: String, #[serde(default = "default_true")] create_if_missing: bool, }, } impl DotfileEntry { pub fn path(&self) -> &str { match self { DotfileEntry::Simple(p) => p, DotfileEntry::WithOptions { path, .. } => path, } } pub fn create_if_missing(&self) -> bool { match self { DotfileEntry::Simple(_) => true, DotfileEntry::WithOptions { create_if_missing, .. } => *create_if_missing, } } /// Validate path safety (prevent traversal attacks) pub fn is_safe_path(&self) -> bool { let path = self.path(); !path.contains("..") && !path.starts_with('/') } } impl Config { pub fn load() -> Result { let path = Self::config_path()?; // ~/.tether/config.toml let content = std::fs::read_to_string(path)?; Ok(toml::from_str(&content)?) } pub fn save(&self) -> Result<()> { let path = Self::config_path()?; let content = toml::to_string_pretty(self)?; crate::sync::atomic_write(&path, content.as_bytes()) } } // Example config.toml: /* [sync] interval = "5m" strategy = "last-write-wins" [backend] type = "git" url = "git@github.com:user/tether-sync.git" [packages] remove_unlisted = false [packages.brew] enabled = true sync_casks = true sync_taps = true [packages.npm] enabled = true sync_versions = false [dotfiles] files = [ { path = ".zshrc", create_if_missing = false }, { path = ".gitconfig", create_if_missing = true }, ".zprofile", ] dirs = [".config/nvim"] [security] encrypt_dotfiles = true scan_secrets = true */ // Example usage: let mut config = Config::load()?; // Add new dotfile config.dotfiles.files.push(DotfileEntry::Simple(".tmux.conf".to_string())); // Enable bun package sync // Assuming a 'bun' field exists within config.packages // config.packages.bun.enabled = true; // Save changes config.save()?; ``` -------------------------------- ### GitHub Actions Workflow for Fly.io Deployment Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md YAML configuration for a GitHub Actions workflow that automatically deploys the Tether CLI website to Fly.io on every push to the main branch. It uses the `superfly/flyctl-actions/setup-flyctl@master` action and requires the `FLY_API_TOKEN` secret. ```yaml name: Deploy to Fly.io on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: superfly/flyctl-actions/setup-flyctl@master - run: flyctl deploy --remote-only env: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} ``` -------------------------------- ### Rust: Clone Git Repository with Authentication Source: https://context7.com/paddo-tech/tether-cli/llms.txt Clones a Git repository from a given URL to a specified path. This function uses the `git` command-line interface to leverage existing authentication mechanisms (e.g., SSH keys, GitHub CLI). It returns a `GitBackend` instance upon successful cloning or an error if the operation fails. ```rust use git2::Repository; use std::path::{Path, PathBuf}; use std::process::Command; pub struct GitBackend { repo_path: PathBuf, } impl GitBackend { pub fn clone(url: &str, path: &Path) -> Result { // Use git CLI for gh authentication support let output = Command::new("git") .args(["clone", url, path.to_str().unwrap()]) .output()?; if !output.status.success() { let error = String::from_utf8_lossy(&output.stderr); return Err(anyhow::anyhow!("Failed to clone: {}", error)); } Ok(Self { repo_path: path.to_path_buf() }) } // ... other methods } // Example usage: // let sync_path = PathBuf::from("~/.tether/sync"); // let git = GitBackend::clone("git@github.com:user/tether-sync.git", &sync_path)?; ``` -------------------------------- ### Synchronize Environment with Conflict Detection (Rust) Source: https://context7.com/paddo-tech/tether-cli/llms.txt This Rust function synchronizes dotfiles and packages across machines. It handles Git pull/push operations, encrypts/decrypts dotfiles using a provided key, detects and prompts for conflict resolution, and manages package synchronization. Dependencies include `tether::config`, `tether::sync`, `sha2`, and `home` crates. ```rust use tether::config::Config; use tether::sync::{GitBackend, SyncEngine, SyncState}; use sha2::{Digest, Sha256}; pub async fn run(dry_run: bool, force: bool) -> Result<()> { let config = Config::load()?; let sync_path = SyncEngine::sync_path()?; let home = home::home_dir().unwrap(); // Unlock encryption if enabled if config.security.encrypt_dotfiles && !crate::security::is_unlocked() { let passphrase = Prompt::password("Passphrase")?; crate::security::unlock_with_passphrase(&passphrase)?; } // Pull latest changes from Git let git = GitBackend::open(&sync_path)?; git.pull()?; // Decrypt and apply remote dotfiles if config.security.encrypt_dotfiles { let key = crate::security::get_encryption_key()?; for entry in &config.dotfiles.files { let file = entry.path(); // e.g., ".zshrc" let enc_file = sync_path.join("dotfiles").join(format!("{}.enc", file.trim_start_matches('.'))); if enc_file.exists() { let encrypted = std::fs::read(&enc_file)?; let plaintext = crate::security::decrypt_file(&encrypted, &key)?; // Detect conflicts before overwriting let local_file = home.join(file); if let Some(conflict) = detect_conflict(file, &local_file, &plaintext, None) { conflict.prompt_resolution()?; } else { std::fs::write(&local_file, plaintext)?; } } } } // Sync local changes to Git let mut state = SyncState::load()?; for entry in &config.dotfiles.files { let file = entry.path(); let source = home.join(file); if source.exists() { let content = std::fs::read(&source)?; let hash = format!("{:x}", Sha256::digest(&content)); if state.files.get(file).map(|f| f.hash != hash).unwrap_or(true) { // File changed - encrypt and sync let key = crate::security::get_encryption_key()?; let encrypted = crate::security::encrypt_file(&content, &key)?; let dest = sync_path.join("dotfiles").join(format!("{}.enc", file.trim_start_matches('.'))); std::fs::write(&dest, encrypted)?; state.update_file(file, hash); } } } // Import missing packages (Homebrew, npm, etc.) import_packages(&config, &sync_path, &machine_state, false, &[]).await?; // Export package manifests sync_packages(&config, &mut state, &sync_path, &machine_state, false).await?; // Commit and push if git.has_changes()? { git.commit("Sync dotfiles and packages", &state.machine_id)?; git.push()?; } Ok(()) } ``` -------------------------------- ### Rust: Commit Changes to Git Repository Source: https://context7.com/paddo-tech/tether-cli/llms.txt Stages all changes in the repository, writes the index, and creates a new commit with a specified message and machine ID. It uses the `git2` crate for repository operations and requires a previous commit to exist as a parent. Errors during staging or commit will be returned. ```rust use git2::{Repository, Signature}; use std::path::PathBuf; impl GitBackend { // ... clone and pull methods pub fn commit(&self, message: &str, machine_id: &str) -> Result<()> { let repo = Repository::open(&self.repo_path)?; let mut index = repo.index()?; index.add_all(["*".to_string()].iter(), git2::IndexAddOption::DEFAULT, None)?; index.write()?; let oid = index.write_tree()?; let tree = repo.find_tree(oid)?; let sig = Signature::now(machine_id, "tether@local")?; let parent = repo.head()?.peel_to_commit()?; repo.commit(Some("HEAD"), &sig, &sig, message, &tree, &[&parent])?; Ok(()) } // ... other methods } // Example usage: // git.commit("Update .zshrc", "macbook-pro")?; ``` -------------------------------- ### Update GitHub Repository Links Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md Shell command to recursively search for instances of 'username/tether-cli' within the src directory of the Tether CLI website project. This is used to identify files that need updating with the correct GitHub repository path. ```bash grep -r "username/tether-cli" src/ ``` -------------------------------- ### Generate Fly.io Deploy Token Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md Command to generate a deploy token for Fly.io, used for setting up continuous deployment with GitHub Actions. The token is set to expire after 999999 hours. ```bash fly tokens create deploy -x 999999h ``` -------------------------------- ### AES-256-GCM Encryption and Decryption in Rust Source: https://context7.com/paddo-tech/tether-cli/llms.txt Implements AES-256-GCM authenticated encryption and decryption for files. It uses random nonces for each encryption and verifies data integrity during decryption. Requires the 'aes-gcm' and 'rand' crates. Inputs are plaintext byte slices and a 32-byte key; outputs are encrypted byte vectors or decrypted byte vectors. Handles potential errors during encryption/decryption and key generation. ```rust // src/security/encryption.rs use aes_gcm::{Aes256Gcm, KeyInit, Aead}; use rand::RngCore; const NONCE_SIZE: usize = 12; // 96 bits for GCM pub const KEY_SIZE: usize = 32; // 256 bits pub fn generate_key() -> [u8; KEY_SIZE] { let mut key = [0u8; KEY_SIZE]; OsRng.fill_bytes(&mut key); key } pub fn encrypt(plaintext: &[u8], key: &[u8]) -> Result> { let cipher = Aes256Gcm::new_from_slice(key)?; // Generate random nonce let mut nonce_bytes = [0u8; NONCE_SIZE]; OsRng.fill_bytes(&mut nonce_bytes); // Encrypt with authenticated encryption let ciphertext = cipher.encrypt((&nonce_bytes).into(), plaintext)?; // Format: [nonce (12 bytes)][ciphertext + auth tag] let mut result = Vec::with_capacity(NONCE_SIZE + ciphertext.len()); result.extend_from_slice(&nonce_bytes); result.extend_from_slice(&ciphertext); Ok(result) } pub fn decrypt(encrypted_data: &[u8], key: &[u8]) -> Result> { if encrypted_data.len() < NONCE_SIZE { return Err(anyhow::anyhow!("Encrypted data too short")); } let (nonce_bytes, ciphertext) = encrypted_data.split_at(NONCE_SIZE); let cipher = Aes256Gcm::new_from_slice(key)?; // Decrypt and verify authentication tag let plaintext = cipher.decrypt(nonce_bytes.into(), ciphertext)?; Ok(plaintext) } // Example usage: let key = generate_key(); let plaintext = b"export PATH=/usr/local/bin:$PATH"; // Encrypt let encrypted = encrypt(plaintext, &key)?; assert!(encrypted.len() > plaintext.len()); // Nonce + auth tag overhead // Decrypt let decrypted = decrypt(&encrypted, &key)?; assert_eq!(decrypted, plaintext); // Wrong key fails authentication let wrong_key = generate_key(); assert!(decrypt(&encrypted, &wrong_key).is_err()); ``` -------------------------------- ### Rust: Check for Uncommitted Git Changes Source: https://context7.com/paddo-tech/tether-cli/llms.txt Checks if there are any uncommitted changes in the Git repository by running `git status --porcelain`. If the output is not empty, it indicates that there are changes, and the function returns `true`. Otherwise, it returns `false`. ```rust use std::process::Command; impl GitBackend { // ... clone, pull, commit, and push methods pub fn has_changes(&self) -> Result { let output = Command::new("git") .args(["status", "--porcelain"]) .current_dir(&self.repo_path) .output()?; Ok(!output.stdout.is_empty()) } } // Example usage: // if git.has_changes()? { // // perform actions if changes exist // } ``` -------------------------------- ### Rust: Push Git Commits with Retry Logic Source: https://context7.com/paddo-tech/tether-cli/llms.txt Pushes local commits to the `origin/main` branch. It includes a retry mechanism for up to 3 attempts, specifically handling "fetch first" or "non-fast-forward" errors by attempting to pull before retrying the push. If the push fails after retries, an error is returned. ```rust use std::process::Command; impl GitBackend { // ... clone, pull, and commit methods pub fn push(&self) -> Result<()> { // Retry on remote rejection for attempt in 1..=3 { let output = Command::new("git") .args(["push", "origin", "main"]) .current_dir(&self.repo_path) .output()?; if output.status.success() { return Ok(()); } let error = String::from_utf8_lossy(&output.stderr); if (error.contains("fetch first") || error.contains("non-fast-forward")) && attempt < 3 { self.pull()?; // Pull and retry continue; } return Err(anyhow::anyhow!("Failed to push: {}", error)); } Ok(()) } // ... other methods } // Example usage: // git.push()?; ``` -------------------------------- ### Rust: Pull Git Changes with Rebase and Conflict Handling Source: https://context7.com/paddo-tech/tether-cli/llms.txt Pulls changes from the `origin/main` branch and rebases them onto the current branch to avoid merge commits. If a conflict occurs during rebase, it aborts the rebase, resets the repository to the remote state, and returns an error. This ensures a clean history and safe conflict resolution. ```rust use std::process::Command; impl GitBackend { // ... clone method pub fn pull(&self) -> Result<()> { // Fetch and rebase to avoid merge commits Command::new("git") .args(["fetch", "origin", "main"]) .current_dir(&self.repo_path) .output()?; let rebase_output = Command::new("git") .args(["rebase", "origin/main"]) .current_dir(&self.repo_path) .output()?; if !rebase_output.status.success() { // Conflict - abort and reset to remote // Safe: sync will re-export local state self.abort_rebase()?; self.reset_to_remote()?; } Ok(()) } // Placeholder for helper methods used in pull fn abort_rebase(&self) -> Result<()> { Command::new("git") .args(["rebase", "--abort"]) .current_dir(&self.repo_path) .output()?; Ok(()) } fn reset_to_remote(&self) -> Result<()> { Command::new("git") .args(["reset", "--hard", "origin/main"]) .current_dir(&self.repo_path) .output()?; Ok(()) } // ... other methods } // Example usage: // git.pull()?; // Fetches and rebases changes ``` -------------------------------- ### Customize Branding Colors in Tailwind CSS Source: https://github.com/paddo-tech/tether-cli/blob/main/website/README.md CSS code snippet demonstrating how to customize primary, accent, and background colors for the Tether CLI website using Tailwind CSS v4's `@theme` directive within `src/styles/global.css`. ```css @theme { --color-primary: #00d9ff; /* Cyan */ --color-accent: #bd93f9; /* Purple */ --color-background: #0a0e14; /* Dark */ /* ... */ } ```