a member's terminal looks like the owner's
A new Linux account opens a shell with nothing: useradd copies /etc/skel, which on Ubuntu is a bash rc, and the account's shell is zsh — so it got no prompt, no history, no completion, no colour. "Their own account" should not mean a worse terminal than the owner's. src/servers/shell-skel/zshrc is the template, and scripts/starship.toml is reused rather than copied: setup.sh already deploys it for the owner, so one file serves both audiences and they cannot drift. Seeded by provisionOsAccount, which means the retry button applies it to accounts that already exist — no delete-and-recreate. The template depends on nothing but zsh. Starship, eza, nvim, bun, deno and cargo are each used only if present, and every path is $HOME-relative — the owner's own .zshrc has three absolute /home/pastilhas paths in it, which is exactly what a template must not inherit. Without starship it falls back to a zsh prompt showing the same information, because a shell that opens with a broken prompt reads as a broken machine. Never overwrites: written only when the file is ABSENT. ~/.zshrc.local is sourced last and never written, so there is somewhere to put your own config that no future template can reach. Three fixes found by running it: - install -D creates missing parents but applies -o/-g only to the FILE, so ~/.config came out root:root — readable but not writable by its owner, which would have surfaced weeks later as one tool mysteriously failing. The parent is now created explicitly. - useradd took its shell from process.env.SHELL, which under PM2 is whatever PM2 was launched from. A member's shell depended on how the server happened to be started. Now chosen from what is installed: zsh, else bash. - the pty sidecar spawned ITS $SHELL for a member, not theirs. It now execs their passwd shell via sh -c, so the login shell in /etc/passwd is the one they get. starship moves out of the light-profile skip. The light profile exists to serve a file browser, a terminal and chat — the terminal is one of its three reasons to be, and it is what every member gets. Leaving starship out meant the fallback prompt on exactly the installs most likely to have members. oh-my-zsh, eza and lazygit stay full-only. Verified in a real member shell: zsh from passwd, HISTFILE in their own home, eza-backed ll, starship active, EDITOR=nvim, and an edit to .zshrc surviving a reprovision. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
# Officer — default shell configuration.
|
||||
#
|
||||
# Written when your Linux account was created. It is yours: edit it freely. Officer only ever writes this
|
||||
# file if it is missing or still byte-for-byte identical to the template, so your changes survive every
|
||||
# reprovision.
|
||||
#
|
||||
# Deliberately depends on nothing but zsh. Starship, eza, nvim and bun are each used only if present, so
|
||||
# this same file works on a minimal server and on a fully equipped one.
|
||||
|
||||
# ── PATH ──
|
||||
# $HOME-relative throughout. Anything hard-coded to one person's home is a template that only works for
|
||||
# them, which is how the owner's own .zshrc grew three absolute paths.
|
||||
export PATH="$HOME/bin:$HOME/.local/bin:/usr/local/bin:$PATH"
|
||||
[ -d "$HOME/.bun/bin" ] && export PATH="$HOME/.bun/bin:$PATH"
|
||||
[ -d "$HOME/.deno/bin" ] && export PATH="$HOME/.deno/bin:$PATH"
|
||||
[ -d "$HOME/.cargo/bin" ] && export PATH="$HOME/.cargo/bin:$PATH"
|
||||
[ -d "$HOME/.opencode/bin" ] && export PATH="$HOME/.opencode/bin:$PATH"
|
||||
[ -d /opt/nvim-linux-x86_64/bin ] && export PATH="$PATH:/opt/nvim-linux-x86_64/bin"
|
||||
|
||||
# ── History ──
|
||||
# The bits oh-my-zsh would otherwise be pulled in to provide. Shared across concurrent shells, which
|
||||
# matters here: a browser tab and an SSH session are often the same person in the same directory.
|
||||
HISTFILE="$HOME/.zsh_history"
|
||||
HISTSIZE=50000
|
||||
SAVEHIST=50000
|
||||
setopt SHARE_HISTORY # write and read as you go, not only at exit
|
||||
setopt HIST_IGNORE_ALL_DUPS # keep one copy of a repeated command
|
||||
setopt HIST_IGNORE_SPACE # a leading space keeps it out of history
|
||||
setopt HIST_REDUCE_BLANKS
|
||||
setopt EXTENDED_HISTORY # timestamps
|
||||
|
||||
# ── Directories and globbing ──
|
||||
setopt AUTO_CD # `..` and bare directory names change directory
|
||||
setopt AUTO_PUSHD # every cd pushes, so `cd -<TAB>` is a menu
|
||||
setopt PUSHD_IGNORE_DUPS
|
||||
setopt EXTENDED_GLOB
|
||||
setopt INTERACTIVE_COMMENTS # `#` works when pasting a commented command
|
||||
|
||||
# ── Completion ──
|
||||
autoload -Uz compinit
|
||||
# Cache the dump in the account's own home; -C skips the security check on a dump written today, which is
|
||||
# the difference between an instant prompt and a visible pause on every new shell.
|
||||
compinit -d "$HOME/.zcompdump"
|
||||
zstyle ':completion:*' menu select
|
||||
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' # case-insensitive
|
||||
zstyle ':completion:*' list-colors ''
|
||||
setopt COMPLETE_IN_WORD
|
||||
setopt ALWAYS_TO_END
|
||||
|
||||
# ── Keys ──
|
||||
# Emacs bindings explicitly: with EDITOR=nvim zsh would otherwise pick vi mode, which surprises anyone who
|
||||
# did not ask for it.
|
||||
bindkey -e
|
||||
autoload -Uz up-line-or-beginning-search down-line-or-beginning-search
|
||||
zle -N up-line-or-beginning-search
|
||||
zle -N down-line-or-beginning-search
|
||||
bindkey '^[[A' up-line-or-beginning-search # Up: history matching what is already typed
|
||||
bindkey '^[[B' down-line-or-beginning-search
|
||||
bindkey '^[[1;5C' forward-word # ctrl-arrow by word
|
||||
bindkey '^[[1;5D' backward-word
|
||||
bindkey '^[[3~' delete-char
|
||||
bindkey '^[[H' beginning-of-line
|
||||
bindkey '^[[F' end-of-line
|
||||
|
||||
# ── Editor ──
|
||||
if command -v nvim >/dev/null 2>&1; then
|
||||
export EDITOR=nvim VISUAL=nvim SUDO_EDITOR=nvim
|
||||
alias n='nvim'
|
||||
alias vim='nvim'
|
||||
elif command -v vim >/dev/null 2>&1; then
|
||||
export EDITOR=vim VISUAL=vim
|
||||
fi
|
||||
|
||||
# ── Aliases ──
|
||||
if command -v eza >/dev/null 2>&1; then
|
||||
alias ls='eza --group-directories-first'
|
||||
alias ll='eza -l --group-directories-first --git'
|
||||
alias la='eza -la --group-directories-first --git'
|
||||
alias lt='eza --tree --level=2'
|
||||
else
|
||||
alias ls='ls --color=auto --group-directories-first'
|
||||
alias ll='ls -lh'
|
||||
alias la='ls -lah'
|
||||
fi
|
||||
alias grep='grep --color=auto'
|
||||
alias ..='cd ..'
|
||||
alias ...='cd ../..'
|
||||
alias sz='source "$HOME/.zshrc"'
|
||||
command -v duf >/dev/null 2>&1 && alias duf='duf --only local'
|
||||
command -v lazygit >/dev/null 2>&1 && alias lg='lazygit'
|
||||
|
||||
# ── Prompt ──
|
||||
# Starship if it is installed; zsh's own prompt with the same information if not. The fallback exists
|
||||
# because a shell that opens with a broken prompt reads as a broken machine, and a minimal install has
|
||||
# every right not to have starship on it.
|
||||
if command -v starship >/dev/null 2>&1; then
|
||||
eval "$(starship init zsh)"
|
||||
else
|
||||
autoload -Uz vcs_info
|
||||
precmd_vcs_info() { vcs_info }
|
||||
precmd_functions+=( precmd_vcs_info )
|
||||
zstyle ':vcs_info:git:*' formats ' %F{blue}%b%f'
|
||||
setopt PROMPT_SUBST
|
||||
PROMPT='%F{green}%n%f@%F{yellow}%m%f:[%~${vcs_info_msg_0_}]
|
||||
%F{blue}❯%f '
|
||||
fi
|
||||
|
||||
# ── Your own additions ──
|
||||
# Sourced last so anything here wins. Officer never writes to it, so it is the safe place for your own
|
||||
# configuration — and it is why this file can be replaced by a newer template without losing your work.
|
||||
[ -f "$HOME/.zshrc.local" ] && source "$HOME/.zshrc.local"
|
||||
|
||||
# Tool-installed completions and env, if they exist. Each of these appends itself to a shell rc when you
|
||||
# install the tool; sourcing them conditionally keeps that working without hard-coding anyone's home.
|
||||
[ -s "$HOME/.bun/_bun" ] && source "$HOME/.bun/_bun"
|
||||
[ -s "$HOME/.deno/env" ] && source "$HOME/.deno/env"
|
||||
[ -f "$HOME/.cargo/env" ] && source "$HOME/.cargo/env"
|
||||
Reference in New Issue
Block a user