Documentation
¶
Overview ¶
Package config resolves runtime variables from the environment and working directory into a cell identity.
Index ¶
- func ClampPort(s string) string
- func DockerAllocatedPorts() map[int]struct{}
- func EnsureBuildDir(buildDir string) error
- func ResolveAvailablePort(preferred string, taken map[int]struct{}) string
- func ResolveBuildDir(cwd, configDir string, projectConfigExists bool) string
- func ResolveConfigDir(getenv func(string) string) string
- func ResolveForwardEntry(entry string, taken map[int]struct{}) string
- func ResolveWorkspaceName(getenv func(string) string) string
- type Config
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ClampPort ¶
ClampPort ensures a port string represents a valid TCP port (1024–65535). If the value exceeds 65535, it subtracts 65535 repeatedly until it fits, then floors at 1024 to stay out of the privileged range. Pure arithmetic — no I/O. Port availability is handled by ResolveAvailablePorts.
func DockerAllocatedPorts ¶
func DockerAllocatedPorts() map[int]struct{}
DockerAllocatedPorts returns the set of host ports currently published by running docker containers. Degrades gracefully: any error (docker absent, daemon down) yields an empty set, falling back to net.Listen-only probing.
func EnsureBuildDir ¶
EnsureBuildDir creates the build context directory if it doesn't exist.
func ResolveAvailablePort ¶
resolveAvailablePort returns preferred if it's free, otherwise scans upward (up to 100 attempts) for the next available port.
Privileged-range fix (2026-05-15): single-digit TMUX panes produce ports like 489/450 (pane "4" + "89"/"50"), which are below 1024 — the kernel only lets root bind there. `net.Listen` from a user-mode `cell` fails with EACCES, and `isPortAvailable` can't distinguish that from EADDRINUSE → every candidate looks "unavailable" → fallback to the conflicting port. Bump <1024 to ≥1024 BEFORE the scan so dockerd's bind actually succeeds (dockerd is root but the host already has the port allocated to another container, which is the real collision we need to detect).
func ResolveBuildDir ¶
ResolveBuildDir returns the build context directory. When projectConfigExists is true, returns cwd/.devcell (project-local). Otherwise falls back to configDir (global).
func ResolveConfigDir ¶
ResolveConfigDir is the one implementation of the global config dir precedence: $XDG_CONFIG_HOME/devcell, then $HOME/.config/devcell.
func ResolveForwardEntry ¶
ResolveForwardEntry normalises a [ports].forward entry into "host:container".
Supported forms:
"3000" → "3000:3000" (same port, both sides) "8080:3000" → "8080:3000" (explicit, unchanged) "8080:" → "<free>:8080" (auto-resolve host port near 8080) "8080:/udp" → "<free>:8080/udp" (protocol preserved on container side)
The trailing-colon form uses ResolveAvailablePort to find a bindable host port starting from the preferred value, skipping docker-allocated ports in taken. A nil taken set skips the docker check.
func ResolveWorkspaceName ¶
ResolveWorkspaceName resolves the workspace name (persistent grouping): DEVCELL_WORKSPACE, then DEVCELL_CELL_NAME (deprecated), then TMUX_SESSION_NAME, then "main".
Types ¶
type Config ¶
type Config struct {
CellID string
CellName string
WorkspaceName string
WorkspaceHome string
ConfigDir string
BuildDir string // build context dir: .devcell/ when project config exists, else ConfigDir
ImageTag string
Image string
ContainerName string
Hostname string
PortPrefix string
VNCPort string
RDPPort string
BaseDir string
HostUser string
HostUID int // host user's numeric UID, passed to container for bind-mount parity
HostHome string
LocalMode bool // DEVCELL_LOCAL_MODE=true — always rebuild image on run
}
Config holds all runtime variables resolved from environment and cwd.
func Load ¶
Load resolves all config fields from cwd and an environment lookup function. Pure — no os.* calls inside.
func LoadFromOS ¶
LoadFromOS resolves config using the real OS environment and working directory.
func (*Config) ResolveAvailablePorts ¶
func (c *Config) ResolveAvailablePorts()
ResolveAvailablePorts checks whether VNCPort and RDPPort are free and replaces them with nearby available ports when they are already bound.