Commit Graph

83 Commits

Author SHA1 Message Date
swanadiva 04d9cfb096 feat: Sprint 5 — xterm.js terminal with WebSocket mock shell, Alpine tab management 2026-07-07 13:39:35 +07:00
swanadiva 941a67b6ea feat: Sprint 4 — SFTP dual-pane with per-type icons, breadcrumb, drop-zone, create/delete, toast 2026-07-07 13:35:01 +07:00
swanadiva c5ac07e27f feat: Sprint 3 — settings page with tabs/toggles/devices/danger-zone, brief page 2026-07-07 13:31:13 +07:00
swanadiva c4b0d7d8c0 feat: Sprint 2 — snippets + keychain CRUD, standalone templates, clipboard/utils JS 2026-07-07 13:26:56 +07:00
swanadiva 8cfdec3980 docs: update PROGRESS.md + AGENTS.md to reflect Sprint 1 completion, Sprint 2 in progress 2026-07-07 13:19:33 +07:00
swanadiva 86620b034f feat: Sprint 1 final — delete host, Alpine modal events, grid/list toggle, transfers panel 2026-07-07 13:17:31 +07:00
swanadiva d771925727 feat: Sprint 1 — host model, mock store, dashboard CRUD, HTMX partials 2026-07-07 13:15:56 +07:00
swanadiva 43a19b723a feat: Sprint 0 — GoFiber + HTMX + TailwindCSS v4 scaffolding
- Go module: git.tukangketik.id/swanadiva/hostkeeper/v2
- GoFiber v2 server with static, template engine, middleware
- HTMX + Alpine.js (downloaded from CDN)
- TailwindCSS v4 with custom theme (Lumina System colors)
- Custom CSS: dot-grid, glassmorphism, animations, toggle, modal
- Layout template (sidebar nav + header + main)
- Dashboard page with host list, search, filter, view toggle
- Health endpoint: GET /api/health
2026-07-07 12:18:39 +07:00
swanadiva a0c8483c0e docs: migrate all planning docs from React to GoFiber + HTMX
- New ARCHITECTURE_HTMX.md — comprehensive HTMX architecture doc
- ARCHITECTURE.md — updated to point to HTMX version
- UI_COMPONENTS.md — replaced React tree with HTMX partials
- SPRINT_PLAN.md — all sprint tasks updated for HTMX
- BUILD_SYSTEM.md — simplified (no Vite, no npm)
- TIMELINE.md — 3.5 week HTMX timeline
- PROGRESS.md — updated status + HTMX
- AGENTS.md — updated checkpoint with HTMX decision
2026-07-07 12:15:19 +07:00
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
swanadiva 7794ca554b chore: move V1 plans to v1/docs/plans/ + create root AGENTS.md
- git mv docs/plans/ (V1 planning docs) into v1/docs/plans/
- Create AGENTS.md as AI session checkpoint for seamless continuation
- Root now clean: only V2-related files remain
2026-07-07 12:01:52 +07:00
swanadiva 847989df75 refactor: move V1 code into v1/ subdirectory
- git mv cmd/ internal/ pkg/ test/ go.mod go.sum Makefile build.sh docs/ v1/
- Create v1/README.md with V1 documentation
- Update root README for V1 + V2 structure
- V1 still builds (cd v1 && go build ./cmd/hostkeeper) and 105 tests pass
- Root is now clean for V2 development
2026-07-07 11:56:27 +07:00
swanadiva 8ebdebedc8 chore: V2 planning docs + template discovery 2026-07-07 11:53:16 +07:00
swanadiva 4a8b4a2bc4 test: Phase 3 comprehensive test coverage — 105 tests, zero race conditions
- Add test/crypto/ (19 tests): AES-256-GCM encrypt/decrypt, PBKDF2, IsEncrypted, HashPassword
- Add test/knownhosts/ (14 tests): TOFU verify, MITM detection, CRUD, persistence
- Add test/storage/ (20 tests): KeyPair/Snippet CRUD, encryption, MergeStrategy
- Add test/config/ (9 tests): config lifecycle, path getters
- Add test/tui/ (10 tests): WrapFooter, ClampWidth, TruncateStr
- Fix knownhosts deadlock: Add/Remove use saveInternal()
- Export responsive.go functions for testing
- Add docs/TEST_PLAN.md with full scenario documentation

Coverage: crypto 0%→100%, knownhosts 0%→100%, storage 40%→90%, config 22%→80%, tui 40%→70%
2026-06-29 12:05:02 +07:00
swanadiva 408681c8e4 feat: Phase 2 UX Polish — theme system, config profiles, error banner, tests
- Add Theme struct with 3 predefined themes (dark/light/druntime)
- Add Profile struct for named configuration profiles
- Add ErrorBanner with severity levels and auto-dismiss
- Add unit tests for theme, error banner, and models
- Update CHANGELOG.md and PROJECT_STATE.md
2026-06-29 11:50:46 +07:00
swanadiva 93957e3989 feat: auto-detect encrypted files + CLI --password flag
- Storage.IsDataEncrypted() checks if hosts.json is encrypted
- TUI auto-detects encrypted files, prompts password automatically
- Root command: --password flag for all CLI commands
- newStorage() helper applies password flag to storage
- add/list/edit/delete commands now support encrypted storage
- passwordSetMsg loads hosts after password is set
2026-06-25 14:34:41 +07:00
swanadiva 94f2142d3d feat: encryption password prompt + --encrypt flag
- PasswordPromptTab: setup/unlock modes, password + confirm fields
- --encrypt flag: shows password prompt on TUI startup
- Model.ShowEncryptPrompt() triggers prompt on first render
- passwordSetMsg stores password in Model.storagePassword
- Tab interface: added Close() method to PasswordPromptTab
2026-06-25 13:38:59 +07:00
swanadiva 1d2e29d20a feat: integrate security features into TUI
- SFTPBrowserTab: added storagePassword, passphraseCallback fields
- Model: added storagePassword, knownHosts fields
- cmd/hostkeeper/tui.go: initialize known_hosts on startup
- SFTP connect: wire passphrase callback to SSH client
- SetStoragePassword/SetKnownHosts/SetPassphraseCallback methods
2026-06-25 13:32:59 +07:00
swanadiva 611b794fc7 feat: Phase 2 Security Enhancement
- pkg/crypto: AES-256-GCM encryption with PBKDF2 key derivation
  - 100k iterations, 16-byte salt, SHA-256
  - Encrypt/Decrypt/IsEncrypted/HashPassword
- Storage layer encryption:
  - JSONStorage.SetPassword() enables transparent encrypt/decrypt
  - readJSON auto-decrypts, replace* auto-encrypts
- pkg/knownhosts: TOFU host key verification
  - Verify/Add/Remove host keys
  - HostKeyCallback for SSH config
- SSH client security:
  - SetHostKeyCallback() replaces InsecureIgnoreHostKey()
  - SetPassphraseCallback() for encrypted private keys
  - getKeySigner() tries passphrase on encrypted keys
- Models: AppConfig gains EncryptionEnabled, PasswordHash, KnownHostsFile
2026-06-25 13:28:46 +07:00
swanadiva a1cd3d5dc0 feat: SFTP rename files and directories
- M key enters rename mode with current name pre-filled
- Type new name, Enter to confirm, Esc to cancel
- renameItem: client.Rename() for remote, os.Rename() for local
- Clear cache + refresh after rename
- Footer updated: M:rename
- Filter mode allows M to pass through
2026-06-24 16:27:39 +07:00
swanadiva eb663c2634 fix: SFTP auto-refresh + filter mode + delete refresh
- Clear dirCache before refresh after transfer/delete/mkdir
- Cache was stale: old entries returned instead of fresh data
- Filter mode: allow commands (c,d,n,r) and nav (↑↓,Tab) to pass through
- Filter mode no longer blocks transfer/delete/mkdir/pane-switch
- Delete: clear cache + program.Send() for re-render
- Mkdir: clear cache + program.Send() for re-render
2026-06-24 16:19:56 +07:00
swanadiva 55b5c7b5a0 fix: SFTP auto-refresh after file transfer
- Added program *tea.Program to SFTPBrowserTab and Model
- SetProgram() allows goroutines to send messages to Bubble Tea
- After transfer: program.Send(sftpRefreshMsg{}) triggers re-render
- Model stores program reference, passes to SFTP tab on creation
2026-06-24 14:32:30 +07:00
swanadiva 6b95385094 feat: SFTP file transfer progress bar + auto-refresh
- Progress bar: [████████░░░░] 67% 12.3MB/18.5MB
- progressWriter wraps io.Writer, reports bytes via callback
- Footer shows live progress during upload/download
- Auto-refresh destination pane after transfer completes
- Success message shown for 1 second before clearing
2026-06-24 14:25:11 +07:00
swanadiva a597ea5291 fix: rename SFTP footer C:copy → C:transfer for clarity 2026-06-24 14:11:17 +07:00
swanadiva 8f1f2226f3 perf: SFTP directory listing cache
- Added dirCache map to sftpPane for caching directory listings
- Cache hit: instant navigation (no disk/network I/O)
- Cache miss: read from disk/SFTP, store in cache per path
- R key clears current directory cache and forces fresh read
- Significant speedup when navigating back to previously visited folders
2026-06-24 11:46:17 +07:00
swanadiva 2a8940211c docs: update project status — SFTP polish done, next sprint planned
- Updated project phase to Phase 2
- Next sprint: SFTP performance + file transfer
- Final sprint: security + UX polish
2026-06-24 11:43:36 +07:00
swanadiva 25a53d990b fix: SFTP default to Local pane + fixed border height
- Default active pane changed from Remote to Local on SFTP init
- renderPane now takes maxH parameter for fixed border height
- paneStyle.Height(maxH) prevents border from shrinking/growing on scroll
- Stacked mode: maxH = t.height - 6; Side-by-side: t.height - 5
2026-06-24 11:30:54 +07:00
swanadiva 2e10308c75 fix: SFTP stacked mode — render only active pane + indicator bar
Stacked mode (<50 cols) now shows only the active pane (Local/Remote)
with a visual indicator bar. Tab switches between panes. Side-by-side
mode (>=50 cols) unchanged.
2026-06-24 11:22:21 +07:00
swanadiva c114b2435c docs: document SFTP stacked mode fix plan for next agent 2026-06-23 19:34:55 +07:00
swanadiva 0ab4b5211d docs: update CHANGELOG with SFTP pane width fix details 2026-06-23 19:24:36 +07:00
swanadiva ebd72cf16c fix: SFTP pane width — account for border in halfW calculation, fix innerW to maxW-2 (padding only), truncate filter line
Root cause: lipgloss Width(maxW) = content area inside border, border adds 2 chars extra.
- halfW was t.width/2, should be t.width/2-2 (reserve border per pane)
- innerW was maxW-4, should be maxW-2 (padding only, not border)
- Each pane total = maxW + 2 (content + border)
2026-06-23 19:22:58 +07:00
swanadiva 2cc9392e2b fix: SFTP pane truncation — use lipgloss.Width instead of len(), account for border+padding overhead, compact file listing on narrow panes 2026-06-23 19:15:21 +07:00
swanadiva d75621e9b4 feat: responsive TUI layout — mobile/tablet/desktop support
- NEW responsive.go: wrapFooter, adaptiveSidePad, clampWidth, truncateStr
- Footer auto-wraps to multi-line on narrow terminals (full labels preserved)
- Box width clamped to terminal width across all tabs
- Host/key/snippet rows truncated with ellipsis; compact format <35 cols
- SFTP panes stack vertically when terminal < 50 cols
- Tab bar truncates names on overflow
- Form contentW minimum lowered 50->30 for mobile
- Fixed: key_list_tab & snippet_list_tab dropped last data row (off-by-one bug)
2026-06-23 19:08:44 +07:00
swanadiva d359688b75 docs: add responsive layout plan to PROJECT_STATE.md and CHANGELOG.md 2026-06-23 19:01:31 +07:00
swanadiva a6850b577c docs: update CHANGELOG.md and PROJECT_STATE.md with all fixes 2026-06-23 18:49:07 +07:00
swanadiva 7d41391e13 fix: Space/Left/Right passthrough in host form, key/snippet refresh on save/delete, WindowSize to all tabs, footer improvements 2026-06-23 18:48:50 +07:00
swanadiva 9d0338595d docs: update PROJECT_STATE.md and CHANGELOG.md with recent fixes 2026-06-23 18:21:57 +07:00
swanadiva 07899c154b fix: auto-generate ID+timestamps in storage layer on save 2026-06-23 18:18:10 +07:00
swanadiva 512cf5ce1f fix: add E:edit to footer, generate UUID+timestamps in TUI forms 2026-06-23 18:15:36 +07:00
swanadiva 9b27388455 fix(tui): center rows per-line, fix footers per-context 2026-06-23 18:04:11 +07:00
swanadiva e5d32bd22e fix(tui): unify keybinding footer, remove duplicate status bar 2026-06-23 17:45:06 +07:00
swanadiva 4af555c135 chore: remove committed binary, add to gitignore 2026-06-23 17:15:46 +07:00
swanadiva f9b2337612 fix(tui): restore muted status bar, remove duplicate global keys from tab footers 2026-06-23 17:15:39 +07:00
swanadiva 7f197b9e3a fix(tui): center all tabs, full-screen SFTP, muted inline keybindings 2026-06-23 17:12:12 +07:00
swanadiva c7568e0bf4 feat: clear screen on SSH enter/exit, host list scrolling, 'e' edit key
- tea.Batch(tea.ClearScreen, sshConnectCmd) before SSH starts so TUI
  output doesn't bleed into SSH terminal
- tea.ClearScreen after SSH exits so SSH output doesn't ghost in TUI
- Host list now paginates: only (term_height - 8) / 5 cards shown,
  viewport follows selectedIndex with centered scrolling
- Shows 'N of M hosts' indicator when content is clipped
- Added 'e' key alias for editing host (Ctrl+E or E)
2026-06-23 16:04:38 +07:00
swanadiva 2442920616 feat: centered footer + auth type toggle pills
- Status bar footer centered within terminal width using lipgloss.Width
- Auth Type field replaced with toggle pills (password/key)
  Space/Enter/←/→ cycle between options on the focused field
  Selected type shown with SelectedStyle/TagStyle (green),
  inactive type shown in muted SubtitleStyle
  Help hint 'Space/←/→ to toggle' shown when focused
- Added toggleAuthType() and cycleAuthType() helpers
2026-06-23 15:59:54 +07:00
swanadiva 5b456104e8 fix: form tab input not responding to typing
Bug: t.inputs[t.focus].Update(msg) discarded the returned textinput.Model,
so typed characters were never stored in the input state.

Fix: capture both updated model and cmd from textinput.Update():
  t.inputs[t.focus], cmd = t.inputs[t.focus].Update(msg)
  return t, cmd

Same fix applied to all 3 forms (host, key, snippet).
Also moved ctrl+s out of default to its own case for clarity.
2026-06-23 15:53:32 +07:00
swanadiva daa20ac72b fix: sshCmd closure bug + error display
CRITICAL BUG: sshConnectCmd wrapped tea.ExecProcess inside an extra
closure, so Bubble Tea never executed the SSH process — Enter appeared
to do nothing.

Fix:
- sshConnectCmd now returns tea.ExecProcess directly (no extra closure)
- tea.ExecProcess handles all process lifecycle (start, PTY, exit)
- sshExitMsg errors are shown in host list view (ErrorStyle)
- Error routed via Model.Error → HostListTab.err → View()
2026-06-23 15:50:20 +07:00
swanadiva 79f3917a66 fix: cap vertical padding + horizontal centering per line
- 2 lines top padding instead of aggressive vertical centering
- centerText() uses lipgloss.Width for accurate ANSI-aware centering
- Each card line centered individually within terminal width
- Card width capped at 74 chars
2026-06-23 15:45:13 +07:00
swanadiva 53db03814e feat: centered card-style host list layout
- Each host rendered as a bordered card (HostCardStyle / HostCardActiveStyle)
- Title centered horizontally
- Content constrained to 80 columns max
- Vertical centering padding
- Selected host card gets green border (gbGreen #a9b665)
- Empty state message centered
- Removed old plain-text renderHost/renderSelectedHost functions
2026-06-23 15:42:03 +07:00