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
- Variables
- func Dial(ctx context.Context, h Host, addr string) (net.Conn, error)
- func DialLoopback(ctx context.Context, h Host, port int) (net.Conn, error)
- func IsBinary(data []byte, truncated bool) bool
- func Join(words ...string) string
- func LinkLost(err error) bool
- func LoginShell() string
- func ProbePort(ctx context.Context, h Host, port int, timeout time.Duration) bool
- func Quote(s string) string
- func ReadBytes(pid int) (uint64, bool)
- func RealPath(ctx context.Context, h Host, p string) (string, error)
- func Remove(ctx context.Context, h Host, p string) error
- type AddRequest
- type AuthNeed
- type CommandNotFoundError
- type Config
- type Creds
- type DirEntry
- type DirListing
- type ExecResult
- type ExecSpec
- type FileContent
- type FileStat
- type ForegroundSignaler
- type Foregrounder
- type GitInfo
- type HookForward
- type Host
- type HostKeyInfo
- type Info
- type Local
- func (l *Local) Config() Config
- func (l *Local) Connected() bool
- func (l *Local) Has(cmd string) bool
- func (l *Local) ID() string
- func (l *Local) Info() Info
- func (l *Local) ListDir(_ context.Context, p string) (*DirListing, error)
- func (l *Local) LoginPath() string
- func (l *Local) Mkdir(_ context.Context, p string) error
- func (l *Local) OpenRaw(_ context.Context, p string) (io.ReadCloser, *FileStat, error)
- func (l *Local) Probe(ctx context.Context, commands []string) (*ProbeResult, error)
- func (l *Local) ReadAt(_ context.Context, p string, off, n int64) ([]byte, *FileStat, error)
- func (l *Local) ReadFile(_ context.Context, p string, max int64) (*FileContent, error)
- func (l *Local) Resolve(p string) (string, error)
- func (l *Local) Shell() string
- func (l *Local) Start(spec StartSpec) (Proc, error)
- func (l *Local) Stat(_ context.Context, p string) (*FileStat, error)
- func (l *Local) WriteFile(_ context.Context, p string, data []byte, opt WriteOptions) (*FileStat, error)
- type PipeProc
- type ProbeResult
- type Proc
- type Registry
- func (r *Registry) Add(req AddRequest) (*SSH, error)
- func (r *Registry) Close()
- func (r *Registry) Host(id string) (Host, bool)
- func (r *Registry) Info(id string) (Info, bool)
- func (r *Registry) List() []Info
- func (r *Registry) Local() *Local
- func (r *Registry) Probe(ctx context.Context, id string) (Info, error)
- func (r *Registry) RefreshForwards()
- func (r *Registry) Remove(id string) error
- func (r *Registry) SSH(id string) (*SSH, bool)
- func (r *Registry) Start()
- func (r *Registry) Update(id string, name, persist *string) (Info, error)
- type SSH
- func (m *SSH) AcceptHostKey(ctx context.Context, fingerprint string) error
- func (m *SSH) Answer(ctx context.Context, kind, value string, remember bool) error
- func (m *SSH) Close()
- func (m *SSH) Config() Config
- func (m *SSH) Connect(ctx context.Context) error
- func (m *SSH) Connected() bool
- func (m *SSH) EffectivePersist() string
- func (m *SSH) EnsureLoop()
- func (m *SSH) Exec(ctx context.Context, cmd string) (string, error)
- func (m *SSH) Foreground(ctx context.Context, pid int) (int, string, error)
- func (m *SSH) HookURL() string
- func (m *SSH) ID() string
- func (m *SSH) Info() Info
- func (m *SSH) KillTmux(ctx context.Context, name string) error
- func (m *SSH) ListDir(ctx context.Context, p string) (*DirListing, error)
- func (m *SSH) Mkdir(ctx context.Context, p string) error
- func (m *SSH) NoteCall(failed bool)
- func (m *SSH) OpenRaw(ctx context.Context, p string) (io.ReadCloser, *FileStat, error)
- func (m *SSH) Probe(ctx context.Context, commands []string) (*ProbeResult, error)
- func (m *SSH) ReadAt(ctx context.Context, p string, off, n int64) ([]byte, *FileStat, error)
- func (m *SSH) ReadFile(ctx context.Context, p string, max int64) (*FileContent, error)
- func (m *SSH) RefreshForward()
- func (m *SSH) SignalForeground(ctx context.Context, pid int, sig string) error
- func (m *SSH) Start(spec StartSpec) (Proc, error)
- func (m *SSH) Stat(ctx context.Context, p string) (*FileStat, error)
- func (m *SSH) TmuxHas(ctx context.Context, name string) (bool, error)
- func (m *SSH) TmuxPanePid(ctx context.Context, name string) (int, error)
- func (m *SSH) TmuxSessions(ctx context.Context) ([]string, error)
- func (m *SSH) WriteFile(ctx context.Context, p string, data []byte, opt WriteOptions) (*FileStat, error)
- type SSHConfigHost
- type StartSpec
- type WriteOptions
Constants ¶
const ( DefaultReadMax = 800000 MaxFileBytes = 20 << 20 // fs/raw, fs/write and the read max cap )
File API limits (docs/API-board.md §4).
const ( AuthPassword = "password" AuthPassphrase = "passphrase" )
AuthNeed kinds.
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.
const DefaultExecMaxOutput = 4 << 20
DefaultExecMaxOutput caps stdout/stderr of Exec (docs/API-studio.md §1.1).
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.
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.
const LocalID = "local"
LocalID is the fixed id of "This PC".
Variables ¶
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) )
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") )
var ( ErrNotFound = errors.New("machine not found") ErrLocal = errors.New("This PC cannot be changed or deleted") ErrInvalidSpec = errors.New("invalid machine data") )
var ErrAuthNotNeeded = errors.New("machine is not waiting for this")
ErrAuthNotNeeded: nothing is waiting for this answer (any more).
var ErrCopyIntoItself = errors.New("a folder cannot be copied into itself")
ErrCopyIntoItself: the target of a copy lies inside the folder being copied.
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.
var ErrExists = errors.New("target path already exists")
ErrExists: the target of a rename (or mkdir) already exists.
var ErrFingerprintMismatch = errors.New("fingerprint does not match the host key awaiting confirmation")
ErrFingerprintMismatch: the confirmed fingerprint is not the pending one.
var ErrForwardingDisabled = errors.New("sshd refuses port forwarding (AllowTcpForwarding)")
ErrForwardingDisabled: the SSH server refuses direct-tcpip channels (AllowTcpForwarding no).
var ErrNotConnected = errors.New("machine not connected yet")
ErrNotConnected is returned by Start when the machine has no live link.
var ErrPortClosed = errors.New("port closed")
ErrPortClosed: nothing listens on the loopback port.
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 ¶
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 ¶
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 ¶
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 LinkLost ¶
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 Quote ¶
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
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.
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 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 ¶
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 ¶
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.
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.
type HookForward ¶
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 (*Local) Start ¶
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.
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 ¶
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 ¶
StderrTail returns the end of what the program wrote to stderr.
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 ¶
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) RefreshForwards ¶
func (r *Registry) RefreshForwards()
RefreshForwards re-evaluates the hook forward of every SSH machine.
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 ¶
AcceptHostKey records the pending host key if fingerprint matches, then connects.
func (*SSH) Answer ¶
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) EffectivePersist ¶
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) Foreground ¶
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 ¶
HookURL is the NB_HOOK_URL for terminals started now ("" when the forward is not open).
func (*SSH) ListDir ¶
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 ¶
Mkdir creates one remote folder over SFTP (explicit user action only; there is no exec fallback for writes).
func (*SSH) OpenRaw ¶
OpenRaw opens a remote file for streaming. The exec fallback buffers at most MaxFileBytes+1 bytes.
func (*SSH) ReadAt ¶
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) RefreshForward ¶
func (m *SSH) RefreshForward()
RefreshForward opens or closes the forward after a settings change.
func (*SSH) SignalForeground ¶
SignalForeground (SSH) runs remoteSignalScript over exec (3 s timeout).
func (*SSH) TmuxPanePid ¶
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 ¶
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.