Skip to main content

quip-node-manager

Desktop GUI and CLI app for running and monitoring Quip Network nodes, built with Tauri v2 and Rust

설치로 이동

소스 정보

저장소
reason-machines/trending-skills
최근 소스 활동
2026년 4월 30일 17:57
감지된 SKILL.md 언어
영어
스타
82
포크
15

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
quip-node-manager
description
Desktop GUI and CLI app for running and monitoring Quip Network nodes, built with Tauri v2 and Rust
triggers
["manage quip network node","run quip node with GUI","quip node manager setup","configure quip node docker","quip node manager tauri","monitor quip network node","quip node GPU configuration","install quip node manager"]
# Quip Node Manager > Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection. Quip Node Manager is a cross-platform desktop application (macOS, Linux, Windows) built with Tauri v2 + Rust that lets you run, configure, and monitor [Quip Network](https://gitlab.com/quip.network) nodes. It supports two execution modes — Docker (default on Windows/Linux) and Native binary (default on macOS) — with a GUI front-end and an optional terminal UI (`--cli` flag). --- ## Installation ### Quick Install (macOS / Linux) ```sh curl -fsSL https://gitlab.com/quip.network/quip-node-manager/-/raw/main/scripts/install.sh | sh ``` ### Quick Install (Windows PowerShell) ```powershell irm https://gitlab.com/quip.network/quip-node-manager/-/raw/main/scripts/install.ps1 | iex ``` ### Manual Installation | Platform | Format | Steps | |---|---|---| | macOS | `.dmg` | Open DMG, drag to `/Applications`, then run `xattr -dr com.apple.quarantine "/Applications/Quip Node Manager.app"` | | Linux | `.AppImage` | `chmod +x quip-node-manager-linux-x86_64.AppImage && ./quip-node-manager-linux-x86_64.AppImage` | | Linux | `.deb` | `sudo dpkg -i quip-node-manager-linux-x86_64.deb` | | Windows | `.exe` | Run installer; click **More info → Run anyway** if SmartScreen warns | --- ## Development Setup ### Prerequisites - [Rust](https://rustup.rs/) (stable toolchain) - [Bun](https://bun.sh/) or Node.js - Platform Tauri v2 deps: https://v2.tauri.app/start/prerequisites/ ### Clone and Run ```sh git clone https://gitlab.com/quip.network/quip-node-manager.git cd quip-node-manager bun install # Install JS dependencies bun run dev # Launch hot-reloading dev build (opens desktop window) bun run build # Production build for current platform ``` ### Rust-only checks (no frontend needed) ```sh cd src-tauri cargo check # Fast type-check cargo clippy # Lint with suggestions cargo test # Run unit tests ``` --- ## Architecture ``` quip-node-manager/ ├── src/ # Frontend: vanilla HTML/CSS/JS │ ├── index.html │ ├── main.js # Tauri IPC calls (window.__TAURI__) │ └── styles.css ├── src-tauri/ │ ├── src/ │ │ ├── main.rs # App entry point │ │ ├── commands.rs # Tauri IPC command handlers │ │ ├── node.rs # Node process management │ │ ├── config.rs # TOML config generation │ │ ├── docker.rs # Docker mode logic │ │ ├── updater.rs # Background update monitor │ │ └── gpu.rs # CUDA/Metal device detection │ ├── Cargo.toml │ └── tauri.conf.json ├── scripts/ │ ├── install.sh │ └── install.ps1 └── AGENTS.md # Detailed architecture docs ``` **Data directory:** `~/quip-data/` — stores settings, TOML config, secrets, downloaded binaries, and trust database. --- ## Key Concepts ### Run Modes | Mode | Default On | How it works | |---|---|---| | Docker | Windows, Linux | Pulls/manages a container image via Docker daemon | | Native | macOS | Downloads a standalone quip-protocol binary | ### Pre-flight Checklist Before starting the node, the manager verifies: 1. Docker available (Docker mode) or binary downloaded (Native mode) 2. Node secret exists in `~/quip-data/` 3. Public IP reachable 4. Port forwarding configured 5. Firewall rules allow node traffic --- ## Tauri IPC Commands (Frontend → Backend) The frontend calls Rust commands via `window.__TAURI__.core.invoke`. Key commands: ```js const { invoke } = window.__TAURI__.core; // Get current node status const status = await invoke('get_node_status'); // Returns: { running: bool, mode: 'docker'|'native', uptime_secs: number } // Start the node await invoke('start_node'); // Stop the node await invoke('stop_node'); // Get configuration const config = await invoke('get_config'); // Save configuration await invoke('save_config', { config: { /* see config schema below */ } }); // Run pre-flight checks const checks = await invoke('run_preflight'); // Returns: { docker: bool, secret: bool, public_ip: string, port_open: bool, firewall: bool } // Get GPU devices const gpus = await invoke('get_gpu_devices'); // Returns: [{ id: string, name: string, type: 'cuda'|'metal', enabled: bool, utilization: number }] // Check for updates const update = await invoke('check_for_updates'); // Returns: { app: string|null, node: string|null, docker_image: string|null } ``` --- ## Configuration Schema (TOML) The app generates a TOML config written to `~/quip-data/config.toml` matching the quip-protocol format: ```toml [node] mode = "native" # or "docker" secret_path = "/Users/you/quip-data/secret" data_dir = "/Users/you/quip-data" [network] public_ip = "1.2.3.4" port = 9000 tls_cert = "/path/to/cert.pem" # optional tls_key = "/path/to/key.pem" # optional [gpu] enabled = true devices = ["0", "1"] utilization = 80 # percent yield_mode = false [dwave] enabled = false token = "" # set via env: DWAVE_TOKEN daily_budget_seconds = 60 [updates] auto_restart_on_image_update = true check_interval_secs = 1800 ``` --- ## Rust Backend Patterns ### Adding a Tauri Command ```rust // src-tauri/src/commands.rs use tauri::State; use crate::node::NodeManager; #[tauri::command] pub async fn get_node_status( manager: State<'_, NodeManager>, ) -> Result<NodeStatus, String> { manager.status().await.map_err(|e| e.to_string()) } #[tauri::command] pub async fn start_node( manager: State<'_, NodeManager>, ) -> Result<(), String> { manager.start().await.map_err(|e| e.to_string()) } ``` Register in `main.rs`: ```rust // src-tauri/src/main.rs fn main() { tauri::Builder::default() .manage(NodeManager::new()) .invoke_handler(tauri::generate_handler![ commands::get_node_status, commands::start_node, commands::stop_node, commands::get_config, commands::save_config, commands::run_preflight, commands::get_gpu_devices, commands::check_for_updates, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } ``` ### Emitting Live Log Events to Frontend ```rust // src-tauri/src/node.rs use tauri::{AppHandle, Emitter}; pub async fn stream_logs(app: AppHandle, mut reader: impl AsyncBufRead + Unpin) { let mut line = String::new(); loop { line.clear(); match reader.read_line(&mut line).await { Ok(0) => break, // EOF Ok(_) => { app.emit("node-log-line", line.trim().to_string()) .unwrap_or_default(); } Err(e) => { app.emit("node-log-error", e.to_string()).unwrap_or_default(); break; } } } } ``` Listen in the frontend: ```js const { listen } = window.__TAURI__.event; const unlisten = await listen('node-log-line', (event) => { appendToLogDrawer(event.payload); }); // Cleanup when drawer closes: unlisten(); ``` ### Docker Mode: Managing Containers ```rust // src-tauri/src/docker.rs use std::process::Command; pub fn pull_image(image: &str) -> Result<(), String> { let status = Command::new("docker") .args(["pull", image]) .status() .map_err(|e| format!("docker not found: {e}"))?; if status.success() { Ok(()) } else { Err("docker pull failed".into()) } } pub fn run_node_container(image: &str, data_dir: &str, port: u16) -> Result<String, String> { let output = Command::new("docker") .args([ "run", "-d", "--name", "quip-node", "-p", &format!("{port}:{port}"), "-v", &format!("{data_dir}:/quip-data"), image, ]) .output() .map_err(|e| e.to_string())?; if output.status.success() { Ok(String::from_utf8_lossy(&output.stdout).trim().to_string()) } else { Err(String::from_utf8_lossy(&output.stderr).to_string()) } } ``` ### GPU Detection ```rust // src-tauri/src/gpu.rs #[derive(serde::Serialize)] pub struct GpuDevice { pub id: String, pub name: String, pub device_type: String, // "cuda" or "metal" pub enabled: bool, pub utilization: u8, } pub fn detect_gpus() -> Vec<GpuDevice> { let mut devices = Vec::new(); // CUDA detection via nvidia-smi if let Ok(output) = std::process::Command::new("nvidia-smi") .args(["--query-gpu=index,name", "--format=csv,noheader"]) .output() { for line in String::from_utf8_lossy(&output.stdout).lines() { let parts: Vec<&str> = line.splitn(2, ',').collect(); if parts.len() == 2 { devices.push(GpuDevice { id: parts[0].trim().to_string(), name: parts[1].trim().to_string(), device_type: "cuda".into(), enabled: true, utilization: 80, }); } } } // macOS Metal: presence of Metal framework implies GPU #[cfg(target_os = "macos")] devices.push(GpuDevice { id: "0".into(), name: "Apple Metal GPU".into(), device_type: "metal".into(), enabled: true, utilization: 80, }); devices } ``` --- ## CLI Mode ```sh quip-node-manager --cli ``` Launches a terminal UI (TUI) instead of the desktop window — useful for headless servers. --- ## TLS Certificate Setup The GUI includes a built-in walkthrough. For scripted setup: **Let's Encrypt (certbot):** ```sh sudo certbot certonly --standalone -d your.domain.com # Certs written to /etc/letsencrypt/live/your.domain.com/ ``` Then set in config: ```toml [network] tls_cert = "/etc/letsencrypt/live/your.domain.com/fullchain.pem" tls_key = "/etc/letsencrypt/live/your.domain.com/privkey.pem" ``` **Self-signed (openssl):** ```sh openssl req -x509 -newkey rsa:4096 -keyout ~/quip-data/key.pem \
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기