feat(connection): Add LocalConnection implementation (gt-f9x.8)

Implement LocalConnection that provides local file operations, command
execution, and tmux integration:

- File ops: ReadFile, WriteFile, MkdirAll, Remove, RemoveAll, Stat, Glob, Exists
- Command exec: Exec, ExecDir, ExecEnv
- Tmux: NewSession, KillSession, SendKeys, CapturePane, HasSession, ListSessions

Uses proper error wrapping with NotFoundError and PermissionError types.
Integrates with existing internal/tmux package for session management.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
rictus
2026-01-01 19:18:23 -08:00
committed by Steve Yegge
parent ca3c6da8ec
commit b4ff6781b3

View File

@@ -0,0 +1,189 @@
package connection
import (
"io/fs"
"os"
"os/exec"
"path/filepath"
"github.com/steveyegge/gastown/internal/tmux"
)
// LocalConnection implements Connection for local file and command operations.
type LocalConnection struct {
tmux *tmux.Tmux
}
// NewLocalConnection creates a new local connection.
func NewLocalConnection() *LocalConnection {
return &LocalConnection{
tmux: tmux.NewTmux(),
}
}
// Name returns "local" for local connections.
func (c *LocalConnection) Name() string {
return "local"
}
// IsLocal returns true for local connections.
func (c *LocalConnection) IsLocal() bool {
return true
}
// ReadFile reads the named file.
func (c *LocalConnection) ReadFile(path string) ([]byte, error) {
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return nil, &NotFoundError{Path: path}
}
if os.IsPermission(err) {
return nil, &PermissionError{Path: path, Op: "read"}
}
return nil, err
}
return data, nil
}
// WriteFile writes data to the named file.
func (c *LocalConnection) WriteFile(path string, data []byte, perm fs.FileMode) error {
err := os.WriteFile(path, data, perm)
if err != nil {
if os.IsPermission(err) {
return &PermissionError{Path: path, Op: "write"}
}
return err
}
return nil
}
// MkdirAll creates a directory and all parent directories.
func (c *LocalConnection) MkdirAll(path string, perm fs.FileMode) error {
err := os.MkdirAll(path, perm)
if err != nil {
if os.IsPermission(err) {
return &PermissionError{Path: path, Op: "mkdir"}
}
return err
}
return nil
}
// Remove removes the named file or empty directory.
func (c *LocalConnection) Remove(path string) error {
err := os.Remove(path)
if err != nil {
if os.IsNotExist(err) {
return nil // Already gone
}
if os.IsPermission(err) {
return &PermissionError{Path: path, Op: "remove"}
}
return err
}
return nil
}
// RemoveAll removes the named file or directory and any children.
func (c *LocalConnection) RemoveAll(path string) error {
err := os.RemoveAll(path)
if err != nil {
if os.IsPermission(err) {
return &PermissionError{Path: path, Op: "remove"}
}
return err
}
return nil
}
// Stat returns file info for the named file.
func (c *LocalConnection) Stat(path string) (FileInfo, error) {
fi, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return nil, &NotFoundError{Path: path}
}
if os.IsPermission(err) {
return nil, &PermissionError{Path: path, Op: "stat"}
}
return nil, err
}
return FromOSFileInfo(fi), nil
}
// Glob returns the names of all files matching the pattern.
func (c *LocalConnection) Glob(pattern string) ([]string, error) {
matches, err := filepath.Glob(pattern)
if err != nil {
return nil, err
}
return matches, nil
}
// Exists returns true if the path exists.
func (c *LocalConnection) Exists(path string) (bool, error) {
_, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
return true, nil
}
// Exec runs a command and returns its combined output.
func (c *LocalConnection) Exec(cmd string, args ...string) ([]byte, error) {
return exec.Command(cmd, args...).CombinedOutput()
}
// ExecDir runs a command in the specified directory.
func (c *LocalConnection) ExecDir(dir, cmd string, args ...string) ([]byte, error) {
command := exec.Command(cmd, args...)
command.Dir = dir
return command.CombinedOutput()
}
// ExecEnv runs a command with additional environment variables.
func (c *LocalConnection) ExecEnv(env map[string]string, cmd string, args ...string) ([]byte, error) {
command := exec.Command(cmd, args...)
command.Env = os.Environ()
for k, v := range env {
command.Env = append(command.Env, k+"="+v)
}
return command.CombinedOutput()
}
// TmuxNewSession creates a new tmux session.
func (c *LocalConnection) TmuxNewSession(name, dir string) error {
return c.tmux.NewSession(name, dir)
}
// TmuxKillSession terminates a tmux session.
func (c *LocalConnection) TmuxKillSession(name string) error {
return c.tmux.KillSession(name)
}
// TmuxSendKeys sends keys to a tmux session.
func (c *LocalConnection) TmuxSendKeys(session, keys string) error {
return c.tmux.SendKeys(session, keys)
}
// TmuxCapturePane captures the last N lines from a tmux pane.
func (c *LocalConnection) TmuxCapturePane(session string, lines int) (string, error) {
return c.tmux.CapturePane(session, lines)
}
// TmuxHasSession returns true if the session exists.
func (c *LocalConnection) TmuxHasSession(name string) (bool, error) {
return c.tmux.HasSession(name)
}
// TmuxListSessions returns all tmux session names.
func (c *LocalConnection) TmuxListSessions() ([]string, error) {
return c.tmux.ListSessions()
}
// Verify LocalConnection implements Connection.
var _ Connection = (*LocalConnection)(nil)