Skip to content

Version 0.8.0#162

Merged
blacknon merged 36 commits intomasterfrom
develop
Apr 8, 2026
Merged

Version 0.8.0#162
blacknon merged 36 commits intomasterfrom
develop

Conversation

@blacknon
Copy link
Copy Markdown
Owner

@blacknon blacknon commented Apr 8, 2026

lssh v0.8.0

v0.8.0 is a larger minor release from v0.7.1, bringing together several major feature additions.
This release introduces the new TUI multiplexer lsmux and the new one-way sync command lssync. It also includes many practical improvements for day-to-day operations, such as conditional config switching, opening terminals directly from lsmon, and launching the mux UI from lssh.

Highlights

  • Added lsmux

    • Introduces a tmux-like pane-based SSH client
    • Lets you view and operate on multiple hosts at the same time
    • Supports command panes, broadcast input, and pane-local file transfer
    • Reuses the existing lssh host inventory as-is
  • Added lssync

    • Introduces a one-way sync command built on SSH/SFTP
    • Supports local-to-remote, remote-to-local, and remote-to-remote sync without requiring rsync on the remote side
    • Supports deleting destination-only entries with --delete
  • Added conditional config overrides with match / when.*

    • You can now switch settings based on local IP, OS, terminal type, environment variables, and more
    • This makes it easier to handle things like proxy switching by network or hiding hosts depending on where you are connecting from

Improvements

  • Enhanced lsmon

    • You can now open a terminal for the selected host from the top-style viewer with Ctrl + T
    • --share-connect allows terminal sessions to reuse the monitor connection
  • Enhanced lssh

    • Added -P to launch the lsmux-compatible mux UI directly from lssh
    • Added support for --hold and --allow-layout-change to improve multi-host command workflows
  • Enhanced lsshell

    • Added %sync, allowing one-way sync operations directly from inside the shell
  • Improved transfer workflows

    • Refined path resolution and transfer handling around lscp, lsftp, and lssync
  • Updated documentation and packaging

    • Reworked the README to make command roles clearer
    • Updated package layout to make installation by use case easier

Notes

  • lssh, lscp, and lsftp are considered stable
  • lssync, lsmon, lsshell, and lsmux are currently considered beta
  • lsmux and lssync are the main additions in this release, so feedback is especially welcome

Thanks

Main changes included in this release:

  • Added lsmux
  • Added lssync
  • Added conditional configuration with match / when
  • Added terminal integration to lsmon
  • Added lssh -P
  • Updated documentation and demo environment

@blacknon blacknon requested a review from Copilot April 8, 2026 17:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Release bump to v0.8.0 introducing the new mux UI (lsmux), one-way sync (lssync), conditional config overrides (match / when.*), plus monitor/shell workflow improvements.

Changes:

  • Added lssync command + new internal sync engine (internal/sync) and integrations in lsftp / lsshell.
  • Added lsmux pane-based TUI + mux configuration + transfer workflow plumbing.
  • Added conditional server config overrides (match / when.*) and enhanced monitoring terminal integration (lsmon Ctrl+T, --share-connect).

Reviewed changes

Copilot reviewed 82 out of 242 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
mise.toml Extend transfer/sysadmin tasks to include lssync/lsmux.
internal/version/main.go Version bump to 0.8.0; maturity updates.
internal/sync/run_test.go Add tests for sync path helper behavior.
internal/sync/run.go Introduce lssync runtime orchestration (local/remote sync modes).
internal/sync/plan_test.go Add plan-building and delete-scope tests for new sync engine.
internal/sync/plan.go Implement sync planning (desired set + delete scopes).
internal/sync/path.go Add destination/relpath helpers for sync plan building.
internal/sync/filesystem.go Provide local + remote filesystem abstraction for sync/plan/apply.
internal/sync/execute.go Implement plan application (copy, chmod, chtimes, delete).
internal/sync/command_test.go Add parsing tests for lssync-style path/flag parsing.
internal/sync/command.go Implement argument + path spec parsing for sync commands.
internal/ssh/shell.go Refactor port forwarding startup to shared helper.
internal/ssh/run_parallel_forward_test.go Add tests for parallel-forward config selection and notices.
internal/ssh/run.go Add shared-start forwarding helper, parallel-forward config helpers, and ShareConnect flag.
internal/ssh/connect.go Tighten ControlPersist vs ControlMaster behavior; set ControlPersist duration.
internal/ssh/cmd.go Refactor port forwarding startup to shared helper.
internal/sftp/shell.go Add sync built-in command + completion support in lsftp shell.
internal/sftp/path_resolution_test.go Add tests for directory-transfer destination semantics.
internal/sftp/path_resolution.go Add copySourceBase helper used by transfer resolution.
internal/sftp/main.go Update PathSet shape to track root + directory-ness.
internal/sftp/cmd_sync.go Implement lsftp sync built-in using internal/sync engine.
internal/sftp/cmd_put.go Refine put path semantics with root-aware base computation.
internal/sftp/cmd_get.go Refine get task base calculation for directory semantics.
internal/scp/path_resolution_test.go Add tests for directory-copy destination semantics.
internal/scp/path_resolution.go Add copySourceBase helper used by SCP path resolution.
internal/scp/main.go Refine scp push/pull semantics with root-aware base computation.
internal/pshell/shell.go Start parallel-safe forwards for per-host parallel shell sessions.
internal/pshell/complete.go Add %sync completion support in lsshell/pshell.
internal/pshell/cmd_test.go Add test coverage for built-in command detection including %sync.
internal/pshell/cmd.go Implement %sync built-in using internal/sync engine.
internal/mux/transfer_job.go Add transfer job tracking + job launching logic for mux transfers.
internal/mux/transfer_file.go Implement file transfer helpers (local<->remote, remote<->remote) for mux.
internal/mux/remote.go Add mux RemoteSession wrapper + session factory for pane connections.
internal/mux/keys.go Add key binding parsing for configurable mux hotkeys.
internal/monitor/top_terminal.go Add top-panel terminal overlay behavior for lsmon (Ctrl+T).
internal/monitor/top_overlay.go Add overlay primitive to render terminal on top of monitor pane.
internal/monitor/terminal_bridge.go Bridge tvxterm into mview primitives for monitor integration.
internal/monitor/shared_terminal_test.go Add tests for shared terminal factory/close behavior.
internal/monitor/shared_terminal.go Implement shared-connection terminal sessions for lsmon --share-connect.
internal/monitor/panel_base_servers.go Trim server text before node lookup.
internal/monitor/panel_base.go Add global input capture for terminal focus and Ctrl+T terminal open.
internal/monitor/lib.go Wire terminal factories + share-connect flag into monitor runtime.
internal/list/tview.go Add new tview-based selector to mirror classic list UI.
internal/list/select.go Add SelectHosts wrapper that supports cancel behavior.
internal/list/event.go Add cancel-aware selectable key loop for classic list UI.
internal/config/openssh_test.go Make identity-file test deterministic using temp files.
internal/config/main.go Add mux config, conditional match resolution, ignore filtering, and config decoder abstraction.
internal/config/conf_test.go Add coverage for conditional match resolution behavior.
internal/config/conf_struct_server.go Add Ignore + Match/When schemas for conditional overrides.
internal/config/conf_struct_portforward.go Extend port forward struct for tcp/unix networks.
internal/config/conf_struct_mux.go Add mux key binding config with defaults.
internal/common/common_test.go Add tests for ParseForwardSpec tcp/unix parsing.
internal/common/common.go Add ParseForwardSpec; minor prompt printing fix.
internal/app/lssync/app.go Add lssync CLI app using internal/sync engine.
internal/app/lsshell/app.go Add NFS reverse forward flag handling.
internal/app/lssh/app.go Add -P mux UI launcher + opts; update local forward parsing.
internal/app/lsmux/app.go Implement full lsmux CLI app and wire to mux manager.
internal/app/lsmon/app_test.go Add test ensuring lsmon exposes share-connect flag.
internal/app/lsmon/app.go Add --share-connect flag and propagate into ssh Run.
go.mod Update dependencies for mux/terminal UI + sshlib upgrades.
demo/client/home/.lssh.d/servers_match.toml Add demo config for conditional match overrides.
demo/client/home/.lssh.conf Include new servers_match.toml demo config.
demo/client/Dockerfile Build/install lsmux in demo client image.
demo/README.md Document conditional match demo config and examples.
cmd/lssync/main.go Add lssync entrypoint.
cmd/lssync/README.md Add lssync documentation.
cmd/lsshell/README.md Document %sync and new forwarding flag.
cmd/lssh/README.md Document -P mux UI, --hold, unix socket forwarding, etc.
cmd/lsmux/main.go Add lsmux entrypoint.
cmd/lsmux/README.md Add lsmux documentation and mux config reference.
cmd/lsmon/README.md Document Ctrl+T terminal + share-connect flag.
cmd/lsftp/README.md Document sync built-in and sync path prefix conventions.
cmd/lscp/README.md Update CLI help output and version strings.
cmd/README.md Add lssync to command list.
README.md Update suite docs: commands list, install layout, match docs, links.
Makefile Build/install lssync as part of default targets.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


footer.SetDynamicColors(true)
footer.SetText("Ctrl-X[black:#00ffff]ToggleTopPanel[white] ")
footer.SetText("Ctrl-X[black:#00ffff]ToggleTopPanel[white:none]Ctrl-T[white:#ff00ff]OpenTerminal[white]")
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The footer color tag sequence looks malformed ([white:none]) and also removes spacing between the two key hints, which can cause incorrect rendering in the TUI. Consider switching back to standard color tags (e.g., [white]) and adding explicit spacing between the Ctrl-X and Ctrl-T segments.

Suggested change
footer.SetText("Ctrl-X[black:#00ffff]ToggleTopPanel[white:none]Ctrl-T[white:#ff00ff]OpenTerminal[white]")
footer.SetText("Ctrl-X[black:#00ffff]ToggleTopPanel[white] Ctrl-T[white:#ff00ff]OpenTerminal[white]")

Copilot uses AI. Check for mistakes.
Comment on lines +525 to +532
for _, fw := range config.Forwards {
if fw == nil {
continue
}
if err := (&Run{}).startPortForward(connect, fw); err != nil {
errs = append(errs, err)
}
}
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StartParallelForwards calls startPortForward via (&Run{}), which is a code smell and makes it easy to accidentally introduce behavior in startPortForward that depends on Run state. Consider refactoring startPortForward into a package-level helper (no receiver) or making StartParallelForwards a method on Run so it can call r.startPortForward(...) on the actual instance.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +31
func copySourceBase(sourcePath string, sourceIsDir, preserveSourceName bool) string {
sourcePath = filepath.Clean(sourcePath)

if sourceIsDir && !preserveSourceName {
return sourcePath
}

return filepath.Dir(sourcePath)
}
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copySourceBase is now implemented in multiple packages (scp, sftp, and sync) with very similar semantics. This increases the chance of subtle drift over time (especially around directory rename rules). If feasible, consider centralizing this logic in a shared internal helper (or at least adding a comment in each implementation noting that they must remain aligned).

Copilot uses AI. Check for mistakes.
Comment on lines +148 to +154
type sharedTerminalLogWriter struct {
mu sync.Mutex
file *os.File
timestamp bool
removeAnsi bool
pending string
}
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shared-terminal logging/path construction code largely duplicates similar logic in internal/mux/remote.go (log writer, pending buffer, timestamping, ANSI stripping, log path templating). Consider extracting a shared log writer utility to avoid divergence and simplify future fixes (e.g., buffering, error handling, timestamp format changes).

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +71
func (b keyBinding) match(event *tcell.EventKey) bool {
if event == nil {
return false
}
if b.key == tcell.KeyRune {
return event.Key() == tcell.KeyRune && event.Rune() == b.ch
}
return event.Key() == b.key
}
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keyBinding tracks a modifier mask (mod), but match() ignores it. This is misleading for readers and makes it easy to assume modifiers are enforced when they are not. Either incorporate a modifier check (e.g., only enforce when b.mod != 0) or remove the unused field to keep the model accurate.

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@blacknon blacknon merged commit 1c262e7 into master Apr 8, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants