#!/bin/bash # ============================================================================= # machine-setup — the development environment # ============================================================================= # # Definitions only, like the other lib/ files. [[ -n "${MACHINE_SETUP_DEV_LOADED:-}" ]] && return 0 MACHINE_SETUP_DEV_LOADED=1 # ----------------------------------------------------------------------------- # git # ----------------------------------------------------------------------------- # # Read and written as the account, not as root. `git config --global` writes to # $HOME/.gitconfig, so running it under sudo without -H would write root's. # # ── Why this asks before touching an existing identity ── # # The original set all four values unconditionally on every run. Re-running it on # a machine somebody already uses replaces the name and email they had with # whatever is typed — and prompt_value accepts an empty answer, so pressing # Enter twice wrote `user.name = ""`. An empty name is worse than none at all: # unset makes git refuse to commit and say why, empty makes it commit with a # blank author and never mention it. # # ── And why it is worth being careful about here in particular ── # # docs/agent-git-identity.md: every agent Officer runs commits AS THE OWNER, # because it runs as the owner. So this is not only the human's identity — it is # what `git log` will attribute every agent commit on this machine to. # Run from / rather than wherever the script was launched. # # `git config --global` reads and writes $HOME/.gitconfig and needs no repository # — but git still stats the working directory on the way, looking for one. The # script is typically launched from somewhere under the invoking user's home, # which is 0750, so the target account cannot stat it and every call dies with # # fatal: failed to stat '': Permission denied # # Found because the writes failed silently: the section reported "written" while # nothing had been. Both wrappers now run in a subshell from /, which every # account can stat, and their exit status is checked by the caller. git_get() { (cd / && sudo -H -u "$USERNAME" git config --global --get "$1" 2>/dev/null); } git_set() { (cd / && sudo -H -u "$USERNAME" git config --global "$1" "$2"); } # Is there anything configured at all? git_has_identity() { [[ -n "$(git_get user.name)" || -n "$(git_get user.email)" ]]; } # Ask for a value that must not be empty. The original's prompt accepted empty # and wrote it; this re-asks. ask_required() { local __var="$1" message="$2" default="$3" answer="" while [[ -z "$answer" ]]; do if ! read -rp " ${message}${default:+ [$default]}: " answer; then echo "" fail "No answer." fi answer="${answer:-$default}" [[ -z "$answer" ]] && warn "This one cannot be left blank." done printf -v "$__var" '%s' "$answer" } # ----------------------------------------------------------------------------- # Shell # ----------------------------------------------------------------------------- # # ── One starship config, not two ── # # The platform deploys scripts/setup/starship.toml into every member's home # (os-user-shell.ts), and the comment there calls it "the prompt config the # owner's own install uses — one file, both audiences". That was not true: the # original machine script wrote a DIFFERENT config inline, so the owner got one # prompt and every member got another. This deploys the same file the platform # does, which makes the comment true rather than aspirational. # # It lives one directory up because it is shared with the platform, not owned by # this script. STARSHIP_SRC="${STARSHIP_SRC:-$SCRIPT_DIR/../starship.toml}" user_login_shell() { getent passwd "$USERNAME" | cut -d: -f7; } oh_my_zsh_installed() { [[ -d "${USER_HOME}/.oh-my-zsh" ]]; } install_oh_my_zsh() { # The installer refuses to run unattended over an existing install, so this is # only ever called when there is none. sudo -H -u "$USERNAME" sh -c \ "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended >/dev/null 2>&1 } # `chsh` is what actually changes the login shell. Asked separately from # installing zsh, because having a shell available and being handed it at every # login are different decisions. set_login_shell() { local shell="$1" grep -qxF "$shell" /etc/shells || echo "$shell" >>/etc/shells chsh -s "$shell" "$USERNAME" }