machine

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 7, 2026 License: MIT Imports: 38 Imported by: 0

Documentation

Overview

Package machine abstracts where agent processes run: the hub's own PC (local PTY) or a remote host reached over agentless SSH.

Index

Constants

View Source
const (
	DefaultReadMax = 800000
	MaxFileBytes   = 20 << 20 // fs/raw, fs/write and the read max cap

)

File API limits (docs/API-board.md §4).

View Source
const (
	AuthPassword   = "password"
	AuthPassphrase = "passphrase"
)

AuthNeed kinds.

View Source
const (
	StatusLocal        = "local"
	StatusConnecting   = "connecting"
	StatusConnected    = "connected"
	StatusDisconnected = "disconnected"
	StatusReconnecting = "reconnecting"
	StatusHostKey      = "hostkey"
	// StatusAuth: waiting for a password or passphrase only a person can give.
	StatusAuth  = "auth"
	StatusError = "error"
)

Status values reported to clients.

View Source
const DefaultExecMaxOutput = 4 << 20

DefaultExecMaxOutput caps stdout/stderr of Exec (docs/API-studio.md §1.1).

View Source
const GitNoRepoCode = `git() { command git -c core.fsmonitor=false -c log.showSignature=false "$@"; }; `

GitNoRepoCode makes `git` in a POSIX sh script ignore settings that run a command out of a repository's own config, which can arrive with an archive or a shared folder: core.fsmonitor on anything that reads the index, and gpg.program through log.showSignature on signed commits. Hooks stay, a commit must run them.

View Source
const GitNoRepoFilters = `nb_n=${GIT_CONFIG_COUNT:-0}; set -f; ` +
	`for nb_k in $(command git config --show-scope --name-only --get-regexp '^filter\..*\.(clean|smudge|process|required)$' 2>/dev/null | grep -E '^(local|worktree)[[:space:]]' | cut -f2); do ` +
	`export "GIT_CONFIG_KEY_$nb_n=$nb_k" "GIT_CONFIG_VALUE_$nb_n="; nb_n=$((nb_n+1)); done; ` +
	`set +f; export GIT_CONFIG_COUNT=$nb_n; `

GitNoRepoFilters turns off the filter drivers set in the repository's own config (local or worktree scope, includes too): git runs them on `status` and `diff` for any file whose stat changed. It goes through the environment, so nested shells and xargs get it too, and needs git 2.31. Drivers from the user's global config stay (git-lfs); a driver only in the repo's config means a file it handles can read as modified. Run it inside the repository, in read-only scripts only: staging needs the filters. set -f: a driver named "*" must not expand to a file name.

View Source
const LocalID = "local"

LocalID is the fixed id of "This PC".

Variables

View Source
var (
	// ErrRelativePath: file API paths must be absolute (or start with ~).
	ErrRelativePath = errors.New("path must be absolute (or start with ~)")
	// ErrIsDir: a file operation targeted a folder.
	ErrIsDir = errors.New("path is a folder")
	// ErrMtimeMismatch: fs/write ifMtime did not match the file on disk.
	ErrMtimeMismatch = errors.New("file changed since it was opened (mtime mismatch)")
	// ErrNoSFTP: the remote has no SFTP subsystem; the exec fallback is
	// read-only.
	ErrNoSFTP = errors.New("SFTP is not available on this machine; only reading is supported")
	// ErrFileTooLarge: the file exceeds MaxFileBytes.
	ErrFileTooLarge = fmt.Errorf("file larger than %d MB", MaxFileBytes>>20)
)
View Source
var (
	// ErrPidUnknown: the wrapper pid of a remote console is not known (no
	// agent-start marker yet and no tmux pane to ask).
	ErrPidUnknown = errors.New("console process pid not known yet")
	// ErrSignalRefused: the foreground group failed validation (pgid ≤ 1,
	// the hub's own group, or another terminal session).
	ErrSignalRefused = errors.New("signal refused: the foreground process group is not valid for this console")
)
View Source
var (
	ErrNotFound    = errors.New("machine not found")
	ErrLocal       = errors.New("This PC cannot be changed or deleted")
	ErrInvalidSpec = errors.New("invalid machine data")
)
View Source
var ErrAuthNotNeeded = errors.New("machine is not waiting for this")

ErrAuthNotNeeded: nothing is waiting for this answer (any more).

View Source
var ErrCopyIntoItself = errors.New("a folder cannot be copied into itself")

ErrCopyIntoItself: the target of a copy lies inside the folder being copied.

View Source
var ErrDisconnected = errors.New("connection lost")

ErrDisconnected is returned by Proc.Wait when the transport (SSH connection) dropped while the process may still be alive remotely.

View Source
var ErrExists = errors.New("target path already exists")

ErrExists: the target of a rename (or mkdir) already exists.

View Source
var ErrFingerprintMismatch = errors.New("fingerprint does not match the host key awaiting confirmation")

ErrFingerprintMismatch: the confirmed fingerprint is not the pending one.

View Source
var ErrForwardingDisabled = errors.New("sshd refuses port forwarding (AllowTcpForwarding)")

ErrForwardingDisabled: the SSH server refuses direct-tcpip channels (AllowTcpForwarding no).

View Source
var ErrNotConnected = errors.New("machine not connected yet")

ErrNotConnected is returned by Start when the machine has no live link.

View Source
var ErrPortClosed = errors.New("port closed")

ErrPortClosed: nothing listens on the loopback port.

View Source
var ErrSessionsFull = errors.New("the SSH server refuses new sessions (MaxSessions reached)")

ErrSessionsFull: the SSH server kept refusing a new channel; its MaxSessions were all in use for as long as the hub waited. The link itself is fine.

Functions

func Dial

func Dial(ctx context.Context, h Host, addr string) (net.Conn, error)

Dial opens a TCP connection to addr as machine h sees it: a direct-tcpip channel over the existing SSH connection on a server, so that nothing has to be installed there.

func DialLoopback

func DialLoopback(ctx context.Context, h Host, port int) (net.Conn, error)

DialLoopback opens a TCP connection to 127.0.0.1:port, then [::1]:port, on machine h: a local dial on This PC, a direct-tcpip channel over the existing SSH connection on remote machines (docs/API-studio.md §4.4). Only loopback addresses are ever dialled.

func IsBinary

func IsBinary(data []byte, truncated bool) bool

IsBinary reports whether data looks like a non-UTF-8 / binary file. A truncated buffer may end mid-rune, which is not counted against it.

func Join

func Join(words ...string) string

Join quotes each word and joins with spaces.

func LinkLost

func LinkLost(err error) bool

LinkLost says a call failed because of the connection, not because of what it asked for. A dying link answers in many ways before the hub has noticed it.

func LoginShell

func LoginShell() string

LoginShell returns the user's login shell: $SHELL, then /etc/passwd, then a sensible default. systemd user services often run without $SHELL.

func ProbePort

func ProbePort(ctx context.Context, h Host, port int, timeout time.Duration) bool

ProbePort reports whether a loopback port of h accepts TCP within timeout.

func Quote

func Quote(s string) string

Quote returns s escaped for POSIX sh. Safe strings are returned as-is; anything else is wrapped in single quotes, with each embedded quote written as close-quote, escaped quote, reopen:

it's  ->  'it'\''s'

Never build remote commands by raw concatenation; always Quote.

func ReadBytes added in v0.3.0

func ReadBytes(pid int) (uint64, bool)

ReadBytes is how many bytes the process pid and the processes below it have read so far (rchar of /proc/<pid>/io: files, pipes and sockets alike). It is for This PC, where agents run; false where /proc has no answer, as on macOS or once the process is gone.

func RealPath

func RealPath(ctx context.Context, h Host, p string) (string, error)

RealPath resolves symlinks of p (of its nearest existing parent when p does not exist yet).

func Remove

func Remove(ctx context.Context, h Host, p string) error

Remove deletes one file, symlink or empty folder on h.

Types

type AddRequest

type AddRequest struct {
	Name          string `json:"name"`
	SSHConfigHost string `json:"sshConfigHost"`
	Host          string `json:"host"`
	Port          int    `json:"port"`
	User          string `json:"user"`
	AuthMethod    string `json:"authMethod"`
	PrivateKey    string `json:"privateKey"`
	Passphrase    string `json:"passphrase"`
	Password      string `json:"password"`
	PersistMode   string `json:"persistMode"`
}

AddRequest is the body of POST /api/machines.

type AuthNeed

type AuthNeed struct {
	Kind string `json:"kind"`
	// KeyPath is the key a passphrase is for, as the config says it. "" is the key
	// uploaded for this machine.
	KeyPath string `json:"keyPath,omitempty"`
	// Host is who asks: "user@host", which can be a jump host on the way.
	Host string `json:"host"`
	// Prompt is the server's own question, when it asks through keyboard-interactive.
	Prompt string `json:"prompt,omitempty"`
	// Wrong: the last answer was refused.
	Wrong bool `json:"wrong,omitempty"`
	// CanPassword: asked for a passphrase, but the server would also take a password.
	CanPassword bool `json:"canPassword,omitempty"`
	// contains filtered or unexported fields
}

AuthNeed is what a machine is waiting for.

type CommandNotFoundError

type CommandNotFoundError struct{ Command string }

CommandNotFoundError is returned by Start when the command is not on the login PATH. The session manager prints it in red into the terminal.

func (*CommandNotFoundError) Error

func (e *CommandNotFoundError) Error() string

type Config

type Config struct {
	ID            string       `json:"id"`
	Name          string       `json:"name"`
	Kind          string       `json:"kind"` // "local" | "ssh"
	Host          string       `json:"host"`
	Port          int          `json:"port"`
	User          string       `json:"user"`
	SSHConfigHost string       `json:"sshConfigHost"`
	AuthMethod    string       `json:"authMethod"` // "sshconfig" | "agent" | "key" | "password"
	CredRef       string       `json:"credRef,omitempty"`
	PersistMode   string       `json:"persistMode"` // "auto" | "tmux" | "direct"
	Probe         *ProbeResult `json:"probe,omitempty"`
}

Config is the persisted definition of a machine (machines.json).

type Creds

type Creds struct {
	PrivateKey string `json:"privateKey,omitempty"`
	Passphrase string `json:"passphrase,omitempty"`
	Password   string `json:"password,omitempty"`
	// KeyPassphrases open key files of the hub user, by the path the config gives.
	KeyPassphrases map[string]string `json:"keyPassphrases,omitempty"`
}

Creds are credentials uploaded through the UI (stored encrypted).

type DirEntry

type DirEntry struct {
	Name  string    `json:"name"`
	Dir   bool      `json:"dir"`
	Size  int64     `json:"size"`
	Mtime time.Time `json:"mtime,omitzero"`
}

DirEntry / DirListing are returned by the folder picker. Size and Mtime are missing only on the read-only exec fallback of SSH machines.

type DirListing

type DirListing struct {
	Path    string     `json:"path"`
	Parent  string     `json:"parent"`
	Entries []DirEntry `json:"entries"`
}

type ExecResult

type ExecResult struct {
	ExitCode   int
	Stdout     []byte
	Stderr     []byte
	TimedOut   bool
	IdleKilled bool
	Cancelled  bool
	Truncated  bool
}

ExecResult is the outcome of Exec. ExitCode is -1 when the process was killed (timeout, idle, cancel) or the transport failed.

func Exec

func Exec(ctx context.Context, h Host, spec ExecSpec) (*ExecResult, error)

Exec runs spec on h: locally through os/exec with the login PATH, on SSH over a non-PTY channel in the login shell. A process that outlives its timeout, idles too long or whose ctx is cancelled is stopped (local: SIGTERM to its process group, SIGKILL 3 s later; SSH: signal TERM, then the channel is closed).

type ExecSpec

type ExecSpec struct {
	Cwd string
	// Argv runs a program directly; Script runs a POSIX script instead.
	// Exactly one of them is set.
	Argv   []string
	Script string
	Env    []string // KEY=VALUE
	Stdin  []byte   // nil = /dev/null
	// Timeout bounds the whole run; IdleTimeout kills a run that printed
	// nothing on stdout/stderr for that long. Zero = no limit.
	Timeout     time.Duration
	IdleTimeout time.Duration
	MaxOutput   int64 // default DefaultExecMaxOutput
	// OnStdout, when set, receives stdout chunks as they arrive (from one
	// goroutine), e.g. stream-json lines of a headless CLI.
	OnStdout func([]byte)
}

ExecSpec is one non-interactive command for internal users (runner, git, usage). There is deliberately no public exec endpoint: every caller builds Argv/Script from a fixed template.

type FileContent

type FileContent struct {
	Path      string    `json:"path"`
	Size      int64     `json:"size"`
	Mtime     time.Time `json:"mtime,omitzero"`
	Binary    bool      `json:"binary"`
	Truncated bool      `json:"truncated"`
	Content   string    `json:"content"`
}

FileContent is the API view of fs/read.

type FileStat

type FileStat struct {
	Path   string    `json:"path"`
	Name   string    `json:"name"`
	Dir    bool      `json:"dir"`
	Size   int64     `json:"size"`
	Mtime  time.Time `json:"mtime,omitzero"`
	Exists bool      `json:"exists"`
}

FileStat is the API view of one path (fs/stat, fs/write).

func Copy

func Copy(ctx context.Context, h Host, from, to string, unique bool) (*FileStat, error)

Copy copies a file or folder on h with its links, modes and times, by the machine's own cp so that nothing travels through the hub. An existing target is never replaced: unique takes name-2.ext, name-3.ext, …, otherwise ErrExists.

func Lstat

func Lstat(ctx context.Context, h Host, p string) (*FileStat, bool, error)

Lstat reports p without following a final symlink (Exists:false when missing). Dir is false for a symlink to a folder.

func Rename

func Rename(ctx context.Context, h Host, from, to string) (*FileStat, error)

Rename moves from to to on h; an existing target is never replaced.

type ForegroundSignaler

type ForegroundSignaler interface {
	SignalForeground(ctx context.Context, wrapperPid int, sig string) error
}

ForegroundSignaler is implemented by procs that can stop/continue the foreground process group of their terminal. sig is "STOP" or "CONT"; wrapperPid is the pid from the agent-start marker (remote only).

type Foregrounder

type Foregrounder interface {
	Foreground(ctx context.Context, wrapperPid int) (pgid int, comm string, err error)
}

Foregrounder is implemented by procs that can tell which process group owns the terminal (docs/API-agents.md §6.5). wrapperPid is the PID the wrapper reported in its agent-start marker; local procs ignore it and ask the PTY master directly.

type GitInfo

type GitInfo struct {
	IsRepo  bool   `json:"isRepo"`
	Branch  string `json:"branch"`
	Ahead   int    `json:"ahead"`
	Behind  int    `json:"behind"`
	Changed int    `json:"changed"`
	Error   string `json:"error"`
}

GitInfo is the read-only repo summary shown on the project home screen.

func GitStatus

func GitStatus(ctx context.Context, h Host, dir string) *GitInfo

GitStatus runs gitScript on the machine (5 s timeout). Failures are reported in GitInfo.Error, never as a write or a retry.

type HookForward

type HookForward struct {
	Port  int    `json:"port,omitempty"`
	Error string `json:"error,omitempty"`
}

HookForward reports the remote loopback port forwarded to the hub, or why it could not be opened.

type Host

type Host interface {
	ID() string
	Info() Info
	Connected() bool
	Start(spec StartSpec) (Proc, error)
	Probe(ctx context.Context, commands []string) (*ProbeResult, error)
	ListDir(ctx context.Context, path string) (*DirListing, error)

	// File API (docs/API-board.md §4). Paths are absolute or start with ~.
	Stat(ctx context.Context, path string) (*FileStat, error)
	ReadFile(ctx context.Context, path string, max int64) (*FileContent, error)
	// ReadAt returns up to n bytes of a regular file starting at off
	// (fewer at EOF), plus its stat. Used for transcript tails and
	// fs/read offset/tail.
	ReadAt(ctx context.Context, path string, off, n int64) ([]byte, *FileStat, error)
	OpenRaw(ctx context.Context, path string) (io.ReadCloser, *FileStat, error)
	WriteFile(ctx context.Context, path string, data []byte, opt WriteOptions) (*FileStat, error)
	// Mkdir creates one folder (parent must exist; an existing folder is
	// fine). Only for explicit user actions such as reply/save.
	Mkdir(ctx context.Context, path string) error
}

Host is a machine the session manager can launch processes on.

type HostKeyInfo

type HostKeyInfo struct {
	Fingerprint string `json:"fingerprint"`
	KeyType     string `json:"keyType"`
	Host        string `json:"host"`
}

HostKeyInfo describes an SSH host key awaiting user confirmation.

type Info

type Info struct {
	ID               string       `json:"id"`
	Name             string       `json:"name"`
	Kind             string       `json:"kind"`
	Host             string       `json:"host"`
	Port             int          `json:"port"`
	User             string       `json:"user"`
	SSHConfigHost    string       `json:"sshConfigHost"`
	AuthMethod       string       `json:"authMethod"`
	PersistMode      string       `json:"persistMode"`
	EffectivePersist string       `json:"effectivePersist"`
	Status           string       `json:"status"`
	Error            string       `json:"error"`
	PendingHostKey   *HostKeyInfo `json:"pendingHostKey"`
	HostKeyMismatch  bool         `json:"hostKeyMismatch"`
	NeedsAuth        *AuthNeed    `json:"needsAuth"`
	Probe            *ProbeResult `json:"probe"`
	SessionCount     int          `json:"sessionCount"`
	// HookForward is the reverse port-forward used as the HTTP fallback
	// for agent hooks (SSH only; nil when not requested).
	HookForward *HookForward `json:"hookForward,omitempty"`
}

Info is the API view of a machine (Config + live state, no secrets).

type Local

type Local struct {
	// contains filtered or unexported fields
}

Local runs processes on the hub's own machine through creack/pty.

func NewLocal

func NewLocal(cfg Config) *Local

NewLocal builds the local machine. cfg carries the persisted probe cache.

func (*Local) Config

func (l *Local) Config() Config

func (*Local) Connected

func (l *Local) Connected() bool

func (*Local) Has

func (l *Local) Has(cmd string) bool

Has reports whether cmd resolves on the login PATH.

func (*Local) ID

func (l *Local) ID() string

func (*Local) Info

func (l *Local) Info() Info

func (*Local) ListDir

func (l *Local) ListDir(_ context.Context, p string) (*DirListing, error)

ListDir lists a local directory (dirs first).

func (*Local) LoginPath

func (l *Local) LoginPath() string

LoginPath returns the login shell's PATH.

func (*Local) Mkdir

func (l *Local) Mkdir(_ context.Context, p string) error

Mkdir creates one local folder (explicit user action only).

func (*Local) OpenRaw

func (l *Local) OpenRaw(_ context.Context, p string) (io.ReadCloser, *FileStat, error)

OpenRaw opens a local file for streaming.

func (*Local) Probe

func (l *Local) Probe(ctx context.Context, commands []string) (*ProbeResult, error)

Probe runs the same probe script as remote machines, via the login shell.

func (*Local) ReadAt

func (l *Local) ReadAt(_ context.Context, p string, off, n int64) ([]byte, *FileStat, error)

ReadAt reads up to n bytes of a local file starting at off.

func (*Local) ReadFile

func (l *Local) ReadFile(_ context.Context, p string, max int64) (*FileContent, error)

ReadFile reads at most max bytes of a local file.

func (*Local) Resolve

func (l *Local) Resolve(p string) (string, error)

Resolve expands ~ and cleans a file API path (absolute paths only).

func (*Local) Shell

func (l *Local) Shell() string

Shell returns the login shell used for local sessions.

func (*Local) Start

func (l *Local) Start(spec StartSpec) (Proc, error)

Start launches spec in a new PTY. Commands run through the login shell (`$SHELL -lc 'exec cmd args'`) so profile environment applies, mirroring how remote sessions are started.

func (*Local) Stat

func (l *Local) Stat(_ context.Context, p string) (*FileStat, error)

Stat reports a local path; a missing path is Exists:false, not an error.

func (*Local) WriteFile

func (l *Local) WriteFile(_ context.Context, p string, data []byte, opt WriteOptions) (*FileStat, error)

WriteFile writes data in place (explicit user action only). The parent folder must exist; nothing else is created.

type PipeProc

type PipeProc struct {
	Stdin  io.WriteCloser
	Stdout io.Reader
	// contains filtered or unexported fields
}

PipeProc is a long-running program with separate stdin and stdout and no PTY, for framed protocols such as the Language Server Protocol.

func StartPipe

func StartPipe(h Host, spec ExecSpec) (*PipeProc, error)

StartPipe starts spec (Cwd, Argv or Script, Env; the timeouts and Stdin are ignored) on h: locally with the login PATH, on SSH over a non-PTY channel in the login shell. The caller must call Stop.

func (*PipeProc) Done

func (p *PipeProc) Done() <-chan struct{}

Done is closed when the program has exited.

func (*PipeProc) StderrTail

func (p *PipeProc) StderrTail() string

StderrTail returns the end of what the program wrote to stderr.

func (*PipeProc) Stop

func (p *PipeProc) Stop()

Stop ends the program: SIGTERM and closed stdin first, a kill after pipeStopWait. It is safe to call more than once.

type ProbeResult

type ProbeResult struct {
	OS    string `json:"os"`
	Arch  string `json:"arch"`
	Shell string `json:"shell"`
	Home  string `json:"home"`
	Tmux  bool   `json:"tmux"`
	// TmuxVersion is `tmux -V` without the "tmux " prefix ("3.4").
	TmuxVersion string            `json:"tmuxVersion,omitempty"`
	Commands    map[string]string `json:"commands"`
	ProbedAt    time.Time         `json:"probedAt"`
}

ProbeResult is what the hub learned about a machine.

type Proc

type Proc interface {
	io.ReadWriteCloser
	Resize(cols, rows uint16) error
	Signal(sig string) error // "HUP" | "KILL"
	Wait() (exitCode int, err error)
}

Proc is one running terminal process, local or remote.

type Registry

type Registry struct {

	// Callbacks, set before Start.
	OnChange     func(Info)
	OnRemoved    func(id string)
	OnConnect    func(id string)
	SessionCount func(id string) int
	// PresetCommands lists commands the probe should look for.
	PresetCommands func() []string
	// HookHandler serves POST /nb/hook on reverse port-forwards; WantForward
	// says whether SSH machines should open one (settings hookChannel).
	HookHandler http.Handler
	WantForward func() bool
	// Log records what happens to the links (package connlog).
	Log func(connlog.Event)
	// contains filtered or unexported fields
}

Registry owns all machines and persists machines.json.

func OpenRegistry

func OpenRegistry(st *store.Store, box *secret.Box) (*Registry, error)

OpenRegistry loads machines.json.

func (*Registry) Add

func (r *Registry) Add(req AddRequest) (*SSH, error)

Add validates and registers a new SSH machine (not yet connected).

func (*Registry) Close

func (r *Registry) Close()

Close disconnects every SSH machine.

func (*Registry) Host

func (r *Registry) Host(id string) (Host, bool)

Host returns a machine by id.

func (*Registry) Info

func (r *Registry) Info(id string) (Info, bool)

Info returns the API view of one machine.

func (*Registry) List

func (r *Registry) List() []Info

List returns all machines, This PC first.

func (*Registry) Local

func (r *Registry) Local() *Local

Local returns This PC.

func (*Registry) Probe

func (r *Registry) Probe(ctx context.Context, id string) (Info, error)

Probe re-probes a machine.

func (*Registry) RefreshForwards

func (r *Registry) RefreshForwards()

RefreshForwards re-evaluates the hook forward of every SSH machine.

func (*Registry) Remove

func (r *Registry) Remove(id string) error

Remove deletes an SSH machine and its stored credentials.

func (*Registry) SSH

func (r *Registry) SSH(id string) (*SSH, bool)

SSH returns a remote machine by id.

func (*Registry) Start

func (r *Registry) Start()

Start probes This PC and starts connection loops for remote machines.

func (*Registry) Update

func (r *Registry) Update(id string, name, persist *string) (Info, error)

Update renames a machine and/or changes its persist mode.

type SSH

type SSH struct {
	// contains filtered or unexported fields
}

SSH is an agentless remote machine: one TCP connection, one SSH channel per terminal. Nothing is installed or configured on the remote host.

func (*SSH) AcceptHostKey

func (m *SSH) AcceptHostKey(ctx context.Context, fingerprint string) error

AcceptHostKey records the pending host key if fingerprint matches, then connects.

func (*SSH) Answer

func (m *SSH) Answer(ctx context.Context, kind, value string, remember bool) error

Answer gives the connection what it asked for and connects. A passphrase is tried on the key right here, so a typing mistake never reaches the server. With remember the answer is stored encrypted once a connection proved it right; without, it stays in memory for reconnecting until the hub restarts.

func (*SSH) Close

func (m *SSH) Close()

Close disconnects permanently (machine deleted).

func (*SSH) Config

func (m *SSH) Config() Config

func (*SSH) Connect

func (m *SSH) Connect(ctx context.Context) error

Connect dials synchronously. It is a no-op when already connected.

func (*SSH) Connected

func (m *SSH) Connected() bool

func (*SSH) EffectivePersist

func (m *SSH) EffectivePersist() string

EffectivePersist resolves "auto" using the probe cache.

func (*SSH) EnsureLoop

func (m *SSH) EnsureLoop()

EnsureLoop starts the background reconnect loop if it isn't running.

func (*SSH) Exec

func (m *SSH) Exec(ctx context.Context, cmd string) (string, error)

Exec runs a non-interactive command and returns combined output.

func (*SSH) Foreground

func (m *SSH) Foreground(ctx context.Context, pid int) (int, string, error)

Foreground asks ps for the terminal's foreground process group of the wrapper (pid) and its command name; read-only, 3 s timeout.

func (*SSH) HookURL

func (m *SSH) HookURL() string

HookURL is the NB_HOOK_URL for terminals started now ("" when the forward is not open).

func (*SSH) ID

func (m *SSH) ID() string

func (*SSH) Info

func (m *SSH) Info() Info

func (*SSH) KillTmux

func (m *SSH) KillTmux(ctx context.Context, name string) error

KillTmux kills one nb-* tmux session.

func (*SSH) ListDir

func (m *SSH) ListDir(ctx context.Context, p string) (*DirListing, error)

ListDir lists a remote directory over SFTP (with sizes and mtimes), or with a read-only `ls -1pA` when the SFTP subsystem is unavailable.

func (*SSH) Mkdir

func (m *SSH) Mkdir(ctx context.Context, p string) error

Mkdir creates one remote folder over SFTP (explicit user action only; there is no exec fallback for writes).

func (*SSH) NoteCall

func (m *SSH) NoteCall(failed bool)

NoteCall counts a tool call for the link report.

func (*SSH) OpenRaw

func (m *SSH) OpenRaw(ctx context.Context, p string) (io.ReadCloser, *FileStat, error)

OpenRaw opens a remote file for streaming. The exec fallback buffers at most MaxFileBytes+1 bytes.

func (*SSH) Probe

func (m *SSH) Probe(ctx context.Context, commands []string) (*ProbeResult, error)

Probe runs the read-only probe script.

func (*SSH) ReadAt

func (m *SSH) ReadAt(ctx context.Context, p string, off, n int64) ([]byte, *FileStat, error)

ReadAt reads up to n bytes of a remote file starting at off (SFTP, or `tail -c | head -c` through the read-only exec fallback).

func (*SSH) ReadFile

func (m *SSH) ReadFile(ctx context.Context, p string, max int64) (*FileContent, error)

ReadFile reads at most max bytes of a remote file.

func (*SSH) RefreshForward

func (m *SSH) RefreshForward()

RefreshForward opens or closes the forward after a settings change.

func (*SSH) SignalForeground

func (m *SSH) SignalForeground(ctx context.Context, pid int, sig string) error

SignalForeground (SSH) runs remoteSignalScript over exec (3 s timeout).

func (*SSH) Start

func (m *SSH) Start(spec StartSpec) (Proc, error)

Start opens a new channel with a PTY and runs the terminal command.

func (*SSH) Stat

func (m *SSH) Stat(ctx context.Context, p string) (*FileStat, error)

Stat reports a remote path; a missing path is Exists:false.

func (*SSH) TmuxHas

func (m *SSH) TmuxHas(ctx context.Context, name string) (bool, error)

TmuxHas reports whether tmux session name exists (read-only).

func (*SSH) TmuxPanePid

func (m *SSH) TmuxPanePid(ctx context.Context, name string) (int, error)

TmuxPanePid asks tmux for the pid of the console's pane (read-only), used when no agent-start marker reported the wrapper pid.

func (*SSH) TmuxSessions

func (m *SSH) TmuxSessions(ctx context.Context) ([]string, error)

TmuxSessions lists nb-* tmux sessions on the machine.

func (*SSH) WriteFile

func (m *SSH) WriteFile(ctx context.Context, p string, data []byte, opt WriteOptions) (*FileStat, error)

WriteFile writes a remote file over SFTP. This is the only remote write the hub performs, and only on an explicit user action (save, copy into project). There is no exec fallback for writes.

type SSHConfigHost

type SSHConfigHost struct {
	Host         string `json:"host"`
	HostName     string `json:"hostName"`
	User         string `json:"user"`
	Port         int    `json:"port"`
	IdentityFile string `json:"identityFile"`
	ProxyJump    string `json:"proxyJump"`
}

SSHConfigHost is one concrete `Host` entry from ~/.ssh/config.

func ListSSHConfigHosts

func ListSSHConfigHosts() ([]SSHConfigHost, error)

ListSSHConfigHosts returns the non-wildcard Host aliases of the service user's ~/.ssh/config, includes too, with their effective settings.

type StartSpec

type StartSpec struct {
	SessionID string
	Command   string   // "$SHELL" means the machine's login shell
	Args      []string // already chosen (args or resumeArgs)
	Cwd       string   // "" or "~" = home
	Env       []string // KEY=VALUE
	Cols      uint16
	Rows      uint16
	TmuxName  string // remote only: non-empty = run inside tmux session

	// Shell, when set, replaces Command/Args: a POSIX command line (already
	// quoted) run by the login shell, e.g. the agent wrapper
	// `exec /bin/sh -c "$NB_WRAP" nb fresh <id> 0`. Env is exported to it
	// (local: process env; remote: inline `export`).
	Shell string
	// Check is a command that must resolve on the login PATH before a
	// Shell launch (local only; CommandNotFoundError otherwise).
	Check string
}

StartSpec describes the process to launch.

type WriteOptions

type WriteOptions struct {
	// IfMtime, when set, must match the current mtime (else ErrMtimeMismatch).
	IfMtime *time.Time
	// Unique picks name-2.ext, name-3.ext, … when the path already exists.
	Unique bool
}

WriteOptions modify WriteFile.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
⌂ 换网址