Files
swanadiva c215d68c81 refactor: flatten docs/ — move V2 docs from docs/v2/ to docs/
- git mv docs/v2/*.md docs/ (11 planning documents)
- Remove empty docs/v2/ directory
- Update all references: AGENTS.md, CHANGELOG.md, README.md, ARCHITECTURE.md
- Fix outdated repo tree in ARCHITECTURE.md to match actual structure
2026-07-07 12:04:59 +07:00

11 KiB
Raw Permalink Blame History

Changelog

[Unreleased] — V2 Planning Complete (2026-06-29)

Added (V2 Planning Documents)

  • docs/PROGRESS.md — Status tracker for V2 development
  • docs/ARCHITECTURE.md — System architecture (GoFiber + React + Electron)
  • docs/API.md — REST API + WebSocket specification
  • docs/DATA_MODELS.md — Extended data models (Groups, PortForward, Workspace)
  • docs/UI_COMPONENTS.md — React component tree + state management
  • docs/UI_TERMIUS_REFERENCE.md — Termius visual reference
  • docs/SPRINT_PLAN.md — Sprint-by-sprint task breakdown
  • docs/BUILD_SYSTEM.md — Cross-platform build pipeline
  • docs/PERFORMANCE.md — Performance & stability guide

Architecture Decision

  • Backend: GoFiber v2 (fasthttp-based) replacing chi/net/http
  • WebSocket: gofiber/contrib/websocket (fasthttp/websocket) replacing gorilla/websocket
  • Frontend: React 19 + TypeScript + xterm.js + Zustand
  • Desktop: Electron (electron-builder)
  • Mobile: gomobile + WebView

V1 Status (FROZEN)

  • All V1 code (pkg/, internal/, cmd/, test/) is complete and frozen
  • V1 CLI/TUI remains functional alongside V2 GUI
  • 105 tests passing, zero race conditions

[Unreleased] — 2025-01-31

Fixed

  • TUI host list footer now includes Ctrl+E:edit
  • New hosts/keys/snippets created via TUI form now get UUID + timestamps (CreatedAt, UpdatedAt)
  • Storage layer auto-generates UUID + timestamps on save if empty (defense-in-depth)
  • host_form_tab.go: Space/Left/Right keys now passthrough to text input when not on auth type field (fixes typing spaces and cursor navigation)
  • tui.go: Key and snippet list tabs now properly refresh after save/delete (mirrors host flow)
  • tabs.go: WindowSizeMsg now forwarded to ALL tabs, not just the active one (fixes stale dimensions after resize)

Changed

  • All tab footers are now context-specific (no global status bar)
  • SFTP browser uses full-width panes (t.width/2)
  • sftp_browser_tab.go footer: Added Enter/→:open, ←/Backspace:up
  • form tabs footer: Added Shift+Tab:prev, ↑↓:nav

Responsive Layout (Done)

  • NEW responsive.go: Shared helpers (wrapFooter, adaptiveSidePad, clampWidth, truncateStr)
  • Footer auto-wraps to multi-line when terminal is narrow (full labels preserved)
  • Box width clamped to terminal width — no more overflow
  • Host/key/snippet rows truncated with when names are too long; compact row format on narrow screens
  • SFTP panes stack vertically when terminal < 50 cols
  • Tab bar truncates tab names on overflow
  • Form contentW minimum lowered from 50 to 30 for mobile (Termux)
  • Fixed: key_list_tab & snippet_list_tab were dropping last data row (off-by-one in rows[:len(rows)-1])
  • Fixed: SFTP pane width — lipgloss Width(n) renders n+2 chars (border extra). halfW now t.width/2-2 to compensate. File names truncate to within inner text area. Filter line also truncated.
  • Verified: zero overflow at 80, 60, 50 (side-by-side), 40, 30 cols (stacked)

SFTP Stacked Mode Fix (Done)

  • Stacked mode (<50 cols) now renders only the active pane (Local or Remote)
  • Added pane indicator bar: [Local] Remote with active pane highlighted
  • Side-by-side mode (≥50 cols) unchanged — both panes remain visible
  • Tab key now visually switches between panes on narrow terminals
  • Default active pane: Local (was Remote)
  • Border height fix: pane uses fixed Height(maxH) — border no longer shrinks/grows when scrolling
  • renderPane now takes maxH parameter to control content area height
  • Stacked: maxH = t.height - 6; Side-by-side: maxH = t.height - 5
  • Breakpoints: compact (<60), medium (60100), wide (≥100)

SFTP Performance Fix

  • Added directory listing cache (dirCache map[string][]os.FileInfo) to each pane
  • Cache hit: instant navigation (no disk/network call)
  • Cache miss: read from disk/SFTP, store in cache
  • R key now clears cache for current directory and forces re-read
  • Cache is per-path: navigating to a previously visited folder is instant

SFTP File Transfer Progress Bar

  • Added progress bar during upload/download: [████████░░░░] 67% 12.3MB/18.5MB
  • progressWriter wraps io.Writer and reports bytes transferred
  • Footer shows live progress during transfer
  • Auto-refresh destination pane after transfer completes
  • Success message shown for 1 second before clearing

SFTP Auto-Refresh Fix

  • Added program *tea.Program field to SFTPBrowserTab and Model
  • SetProgram() method allows goroutines to send messages to Bubble Tea
  • After transfer: t.program.Send(sftpRefreshMsg{}) triggers re-render
  • Model stores program reference, passes it to SFTP tab on creation

SFTP Bug Fixes

  • Auto-refresh: clear dirCache before refresh after transfer/delete/mkdir
  • Cache was stale after file operations — old entries returned instead of fresh
  • Filter mode: allow command keys (c, d, n, r) and navigation (↑↓, Tab) to pass through
  • Filter mode no longer blocks transfer, delete, mkdir, or pane switch
  • Delete: clear cache + trigger re-render after file removal
  • Mkdir: clear cache + trigger re-render after directory creation

SFTP Rename Feature

  • Added M key to rename files and directories
  • Rename mode: shows input with current name, type new name, Enter to confirm
  • Works on both Local and Remote panes
  • Clears cache and refreshes after rename
  • Footer updated: M:rename added
  • Filter mode allows M to pass through

v1.0.0 (2025-01-30)

Added

  • Initial release of Hostkeeper SSH/SFTP management tool
  • Host management: CRUD operations for SSH hosts (add, list, edit, delete)
  • SSH connections: Native SSH (default) and Go SSH direct mode
  • TUI interface: Interactive host browser using Bubble Tea
  • Export/Import: JSON export and import with merge/replace strategies
  • Cross-platform builds: Support for Linux, macOS, Windows, Termux
  • Shell completion: Bash, Zsh, Fish, and PowerShell support
  • Configuration: File-based credential storage with 0600 permissions
  • Tag and group: Host categorization with tags and groups
  • Search and filter: Filter hosts by group, tag, or text search

Commands

  • hostkeeper add — Add SSH hosts (interactive and flag-based)
  • hostkeeper list — List hosts with table/JSON output
  • hostkeeper connect — Connect to hosts with custom timeout
  • hostkeeper edit — Edit host configurations
  • hostkeeper delete — Delete hosts with confirmation
  • hostkeeper export — Export data to JSON
  • hostkeeper import — Import data with merge/replace
  • hostkeeper tui — Terminal user interface
  • hostkeeper completion — Shell completion generation
  • hostkeeper version — Version information

Technical

  • Cobra CLI framework for command structure
  • Bubble Tea TUI with keyboard navigation
  • Go SSH client for direct connections
  • Comprehensive test suite with unit and integration tests
  • Build automation via Makefile and build.sh

Notes

  • Initial MVP release, all core features functional
  • Encrypted storage planned for future release
  • Interactive shell in Go SSH direct mode not yet available

Phase 2 — Security Enhancement

AES-256-GCM Encryption

  • New pkg/crypto/crypto.go: AES-256-GCM encrypt/decrypt with PBKDF2 key derivation
  • 100,000 iterations, 16-byte salt, SHA-256 key derivation
  • Encrypt(plaintext, password) → base64(salt + nonce + ciphertext)
  • Decrypt(encoded, password) → plaintext
  • IsEncrypted(data) checks if data looks like encrypted content

Storage Layer Encryption

  • JSONStorage now has password field for master encryption key
  • SetPassword(), GetPassword(), IsEncrypted() methods
  • readJSON() auto-decrypts if password is set and data is encrypted
  • replaceHosts/KeyPairs/Snippets() auto-encrypt before writing
  • All existing CRUD operations transparently encrypt/decrypt

Known Hosts Verification

  • New pkg/knownhosts/knownhosts.go: TOFU (Trust-On-First-Use) model
  • KnownHosts manages known_hosts file (JSON format)
  • Verify() checks if host key matches stored key
  • HostKeyCallback() returns cryptossh.HostKeyCallback for SSH config
  • Warns on key mismatch (potential MITM attack)

SSH Client Security

  • Client now supports hostKeyCallback and passphraseCallback
  • SetHostKeyCallback() — replaces InsecureIgnoreHostKey()
  • SetPassphraseCallback() — prompts for passphrase on encrypted keys
  • getKeySigner() tries passphrase callback if key is encrypted

Models Updated

  • AppConfig: added EncryptionEnabled, PasswordHash, KnownHostsFile

Phase 2 UX Polish (Done)

Theme System

  • NEW themes.go: Theme struct with full color palette
  • 3 predefined themes: dark (Gruvbox), light, dracula
  • SetTheme(name) — updates all component styles at runtime
  • GetActiveTheme() — returns current theme
  • All palette vars now derived from active theme

Config Profiles

  • models.go: Profile struct — name, theme, default group, default auth, editor, notes
  • AppConfig.Profiles []Profile — list of named profiles
  • AppConfig.ActiveProfile string — currently active profile
  • GetProfile(name), GetActiveProfile(), AddProfile(), RemoveProfile()
  • Default config includes "default" profile

Enhanced Error Display

  • NEW error_banner.go: ErrorBanner with severity levels (Error/Warning/Info)
  • Structured format: title + detail + numbered hints
  • Auto-dismiss after 5 seconds (configurable)
  • Color-coded: red (error), yellow (warning), blue (info)
  • Show(), Hide(), Update(), View(width) methods

Tests

  • test/tui/theme_test.go: GetTheme, SetTheme, GetActiveTheme, registry
  • test/tui/error_banner_test.go: Show/Hide, AutoDismiss, Severity, View
  • test/models_test.go: DefaultConfig, Profile CRUD

Phase 3 Testing (Done)

Security-Critical Tests (0% → 100%)

  • test/crypto/crypto_test.go (19 tests): DeriveKey, Encrypt/Decrypt round-trip, empty/large/unicode/newlines data, wrong/empty password, IsEncrypted, HashPassword, randomness
  • test/knownhosts/knownhosts_test.go (14 tests): New, Add/Get/Remove CRUD, Verify unknown/match/mismatch (MITM), HostKeyCallback autoAdd, persistence, corrupted file

Core Tests (40% → 90%)

  • test/storage/json_storage_test.go (20 tests): KeyPair CRUD (6), Snippet CRUD (6), encryption (SetPassword, IsDataEncrypted, wrong password), MergeStrategy (merge/replace), edge cases

Config Tests (22% → 80%)

  • test/config/config_test.go (9 tests): New first run, Save, UpdateAppConfig, path getters

UI Tests (40% → 70%)

  • test/tui/responsive_test.go (10 tests): WrapFooter, ClampWidth, TruncateStr

Bug Fixes

  • knownhosts deadlock: Add()/Remove() now call saveInternal() instead of Save() to avoid re-locking
  • responsive.go: Exported WrapFooter, ClampWidth, TruncateStr for testing

Coverage Summary

  • pkg/crypto: 0% → 100% (19 tests)
  • pkg/knownhosts: 0% → 100% (14 tests)
  • pkg/storage: 40% → 90% (20 tests)
  • pkg/config: 22% → 80% (9 tests)
  • pkg/tui: 40% → 70% (10 new tests)
  • Total: 105 tests, all passing, zero race conditions