#!/usr/bin/env bash
#clear
#export PS4='\e[90m+${LINENO} in ${#BASH_SOURCE[@]}>${FUNCNAME[0]}:${BASH_SOURCE[@]##*/} \e[0m'
#set -x

#echo "starting: $0 <LOG_LEVEL=$1>"

# SSH ControlMaster socket path (must match ossh)
: ${OSSH_CONTROL_PATH:="/tmp/ossh-%r@%h:%p"}

user.id.completion() {
  echo "-u -n" 
  echo "-g"
}

user.id() # <options="-u -n"> # shows the user id. Without parameters it shows the also all groups
{
  id "$@"
}

user.ssh.status.completion() {
  echo log
}

user.ssh.status() # <?log> <?sshDir:~/.ssh> # returns 1 if there is no ssh init. use log as argument if you want to see the output
{
  ossh.isInstalled "$@"
}

user.parameter.completion.sshDir() {
  echo "$HOME/.ssh"
  ls -d $HOME/.ssh/ids/*/ 2>/dev/null
}

user.in() { # <sshId> <?sshDir:~/.ssh> # choose an other identity from user list.other.identities. sshDir overrides the base .ssh location
  local sshId="$1"
  if [ -n "$1" ]; then
    shift
  fi

  private.user.get.sshDir "$1"
  [ -n "$1" ] && shift
  local sshBase="$RESULT"

  if [ -z "$CURRENT_SSH_DIR" ]; then
    export CURRENT_SSH_DIR="$sshBase"
    config set CURRENT_SSH_DIR $CURRENT_SSH_DIR
  fi

  case $sshId in
    '')
      important.log "current sshId is: $CURRENT_SSH_DIR"
    ;;
    main)
      CURRENT_SSH_DIR="$sshBase"
      config set CURRENT_SSH_DIR $CURRENT_SSH_DIR
      success.log "new sshId is main: $CURRENT_SSH_DIR"
    ;;
    /*|~/*)
      CURRENT_SSH_DIR="$sshId"
      config set CURRENT_SSH_DIR $CURRENT_SSH_DIR
      success.log "new sshId is: $CURRENT_SSH_DIR"
    ;;
    *)
      CURRENT_SSH_DIR="$sshBase/ids/$sshId"
      config set CURRENT_SSH_DIR $CURRENT_SSH_DIR
      success.log "new sshId is: $CURRENT_SSH_DIR"

    ;;
  esac

  RESULT="$CURRENT_SSH_DIR"
  RETURN="$1"
}

user.parameter.completion.sshId() {
  user.list.other.identities
  echo "main"
}

private.user.get.sshDir() {
  local sshDir="$1"
  if [ -z "$1" ]; then
    sshDir="$CURRENT_SSH_DIR"
  fi
  if [ -z "$sshDir" ]; then
    sshDir="$HOME/.ssh"
  fi
  shift

  create.result 0 "$sshDir" "$1"
  info.log "$RESULT"
  return $(result)
}

user.ssh.get.key.name() { # # creates a good key name fot this user and host
  ossh.key.get.name
}

user.ssh.set.key.name() {
  ossh.key.set.name "$@"
}

user.ssh.get.file.name() { # # gets the actual key file name (instead of the best key name from get.key.name )
  ossh.file.get.name "$@"
}

user.ssh.rootkey.push() {
  local sshConfigName="$1"
  # if [ -z "$1" ]; then
  #   sshConfigName="$CURRENT_SSH_DIR"
  # fi
  # if [ -z "$sshDir" ]; then
  #   sshDir="$HOME/.ssh"
  # fi
  shift

  private.user.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  user.ssh.get.file.name $sshDir
  if [ -n "$1" ]; then
    shift
  fi
  local sshKeyName="$RESULT"

  "$OOSH_DIR/ossh" connection.open "$sshConfigName"
  rsync -avz --mkpath -e "ssh -o ControlPath=$OSSH_CONTROL_PATH" "$sshDir/public_keys/$sshKeyName.public_key" "$sshConfigName:/root/.ssh/public_keys/"
  ssh -o ControlPath="$OSSH_CONTROL_PATH" "$sshConfigName" ". /root/config/user.env; user authorized.keys.update"
}

user.ssh.rootkey.file.push() {
  local sshConfigName="$1"
  # if [ -z "$1" ]; then
  #   sshConfigName="$CURRENT_SSH_DIR"
  # fi
  # if [ -z "$sshDir" ]; then
  #   sshDir="$HOME/.ssh"
  # fi
  shift

  local sshPublicKeyFile="$1"
  if [ -n "$sshPublicKeyFile" ]; then
    shift
    "$OOSH_DIR/ossh" connection.open "$sshConfigName"
    rsync -avz --mkpath -e "ssh -o ControlPath=$OSSH_CONTROL_PATH" "$sshPublicKeyFile" "$sshConfigName:/root/.ssh/public_keys/"
    ssh -o ControlPath="$OSSH_CONTROL_PATH" "$sshConfigName" ". /root/config/user.env; user authorized.keys.update"
  else
    error.log "no public key file provided as second parameter"
  fi


}

user.ssh.rootkey.file.revoke() {
  local sshConfigName="$1"
  # if [ -z "$1" ]; then
  #   sshConfigName="$CURRENT_SSH_DIR"
  # fi
  # if [ -z "$sshDir" ]; then
  #   sshDir="$HOME/.ssh"
  # fi
  shift

  local sshPublicKeyFile="$1"
  if [ -n "$sshPublicKeyFile" ]; then
    shift
    ssh -o ControlPath="$OSSH_CONTROL_PATH" $sshConfigName ". /root/config/user.env; mv  /root/.ssh/public_keys/$(basename $sshPublicKeyFile)  /root/.ssh/deactive.public_keys/$(basename $sshPublicKeyFile);    user authorized.keys.update"
  else
    error.log "no public key file provided as second parameter"
  fi


}


user.ssh.rootkey.pull() {
    local sshConfigName="$1"
  # if [ -z "$1" ]; then
  #   sshConfigName="$CURRENT_SSH_DIR"
  # fi
  # if [ -z "$sshDir" ]; then
  #   sshDir="$HOME/.ssh"
  # fi
  shift



  "$OOSH_DIR/ossh" connection.open "$sshConfigName"
  rsync -avz -e "ssh -o ControlPath=$OSSH_CONTROL_PATH" "$sshConfigName:/root/.ssh/id_rsa.pub" "./root.$sshConfigName.public_key"
  #ssh $sshConfigName ". /root/config/user.env; user authorized.keys.update"
}

user.ssh.rootkey.push.completion() {
  private.user.get.sshDir
  local sshDir="$RESULT"
  grep '^Host' $sshDir/config $sshDir/config.d/* 2>/dev/null | cut -d ' ' -f 2-
}

user.ssh.rename.files() { # <sshKeyName> # renames the keys to the new base name <sshKeyName>
  user.ssh.get.file.name
  local sshKeyFileName="$RESULT"

  local sshKeyName="$1"
  if [ -z "$sshKeyName" ]; then
    user.ssh.get.key.name
    sshKeyName="$RESULT"
  fi
  shift

  private.user.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  #ls -al $sshDir/public_keys/${sshKeyFileName}*
  #ls -al $sshDir/private_key/${sshKeyFileName}*

  mv $sshDir/private_key/${sshKeyFileName}.private_key $sshDir/private_key/${sshKeyName}.private_key
  mv $sshDir/public_keys/${sshKeyFileName}.public_key $sshDir/public_keys/${sshKeyName}.public_key 

  tree $sshDir

}

user.init() # <?sshDir:~/.ssh> # creates a new SSH key pair for this user
{
  private.user.get.sshDir "$1"
  [ -n "$1" ] && shift
  local sshDir="$RESULT"

  # Keypair creation: only when ~/.ssh has no key yet. user.ssh.status's
  # `log` arg makes the existing-state path log+ls; both branches fall
  # through to the unconditional WODA-ensure block below.
  if user.ssh.status log "$sshDir"; then
    console.log ".ssh exists"
    if command -v tree >/dev/null 2>&1; then
      tree $sshDir
    else
      ls -la $sshDir
    fi
  else
    console.log "initialising new .ssh in $sshDir"
    mkdir -p $sshDir
    ssh-keygen -t ed25519 -f "$sshDir/id_ed25519" -N ''
    mkdir -p $sshDir/public_keys
    mkdir -p $sshDir/private_key
    user.ssh.get.key.name
    local sshKeyName="$RESULT"
    cp "$sshDir/id_ed25519" "$sshDir/private_key/$sshKeyName.private_key"
    cp "$sshDir/id_ed25519.pub" "$sshDir/public_keys/$sshKeyName.public_key"
  fi

  # Ensure the three WODA Host aliases are in $sshDir/config — runs whether
  # or not ~/.ssh pre-existed. user.init was previously a one-shot keypair-
  # creator that wrote WODA only when generating a fresh key; that meant
  # users whose .ssh was created by ssh-keygen-on-first-login (e.g. test
  # in nakedUbuntu's Dockerfile) silently never got WODA.
  #
  # **NOT using ossh.config.create**: it expects its third arg to be an
  # alias name (e.g. "developking" → expanded to ~/.ssh/ids/developking/
  # id_ed25519), not a literal IdentityFile path. Passing a literal path
  # like "$sshDir/id_ed25519" triggers the path-construction fallback at
  # ossh:315-323 — produces garbage like
  # `IdentityFile /ids//root/.ssh/id_ed25519/id_ed25519`. Verified on Alma
  # post-install (commit f515903 introduced this bug; SSH silently fails to
  # resolve the WODA Host because the IdentityFile path is malformed).
  #
  # Direct heredoc per alias, append-if-missing on the `^Host <alias>$`
  # header — same idempotency contract as the previous ossh.config.create
  # path, but with a literal `IdentityFile ~/.ssh/id_ed25519` so SSH
  # expands `~` per-user at read time (portable across all users).
  touch "$sshDir/config"
  if ! grep -q "^Host WODA.test$" "$sshDir/config" 2>/dev/null; then
    cat >>"$sshDir/config" <<EOF

Host WODA.test
 User root
 Port 22
 HostName 178.254.18.182
 IdentityFile ~/.ssh/id_ed25519
EOF
  fi
  if ! grep -q "^Host WODA.dev.root$" "$sshDir/config" 2>/dev/null; then
    cat >>"$sshDir/config" <<EOF

Host WODA.dev.root
 User root
 Port 22
 HostName cerulean.it
 IdentityFile ~/.ssh/id_ed25519
EOF
  fi
  if ! grep -q "^Host WODA.dev$" "$sshDir/config" 2>/dev/null; then
    cat >>"$sshDir/config" <<EOF

Host WODA.dev
 User developking
 Port 22
 HostName cerulean.it
 IdentityFile ~/.ssh/id_ed25519
EOF
  fi
}

user.ssh.create.folders() { # <?sshDir:~/.ssh> # creates public_keys and private_key folders in <sshDir>
  private.user.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  mkdir -p $sshDir/public_keys
  mkdir -p $sshDir/private_key
  if ! private.detect.ssh.key "$sshDir"; then
    error.log "no ssh key found in $sshDir"
    return 1
  fi
  local keyFile="$RESULT"
  user.ssh.get.key.name
  local sshKeyName="$RESULT"
  cp "$keyFile" "$sshDir/private_key/$sshKeyName.private_key"
  cp "${keyFile}.pub" "$sshDir/public_keys/$sshKeyName.public_key"
}


user.authorized.keys.update() # <?sshDir:~/.ssh> # updates all keys in <sshDir>/public_keys as authorized
{ private.user.update.authorized_keys "$@"; }

private.user.update.authorized_keys() # <?sshDir:~/.ssh> # updates all keys in <sshDir>/public_keys as authorized
{

  private.user.get.sshDir "$1"

  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  if user.ssh.status "" "$sshDir"; then
    info.log "updating $sshDir/authorized_keys"
    rm -f $sshDir/authorized_keys
    cat $sshDir/public_keys/* >>$sshDir/authorized_keys

    chmod 700 $sshDir
    chmod 600 $sshDir/authorized_keys
    if private.detect.ssh.key "$sshDir"; then
      chmod 600 "$RESULT"
    fi
  fi
}

user.get() # <property> <username> # 
{
  local property="$1"
  if [ -n "$1" ]; then shift; fi

  local username="$1"
  if [ -n "$1" ]; then shift; fi

  if os.check private.get.$property "$username"; then
    $RESULT "$username"
  else
    important.log "$RESULT is not supported"
  fi  
  RETURN="$1"
}

user.parameter.completion.property() {
  echo "home"
  echo "basehome"
  echo "shell"
  echo "info"
  echo "name"
}

user.parameter.completion.username() {
  user.list "$@"
}

user.parameter.completion.userName() {
  user.list "$@"
}

user.parameter.completion.groupName() {
  compgen -g "$1"
}

private.get.info.linux() # <username> # 
{
  getent passwd "$1"
  # mac osx
  #dscl . -read /Users/marcel
}

private.get.name.linux() #  # 
{
  id -u -n
}

private.get.name.darwin() #  # 
{
  private.get.name.linux  
}

private.get.basehome.linux() # <username> # 
{
  private.get.basehome.darwin "$@"
}

private.get.basehome.darwin() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then 
    shift; 
  else
    username=$USER
  fi

  if [ "$username" = "root" ]; then
      username="developking"
  fi 
  
  this.absolutePath "$(user.get home $username)/.."
  echo $RESULT
}

private.get.home.linux() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then 
    shift; 
  else
    username=$USER
  fi

  source line 
  private.get.info.linux "$username" \
  | line.split ":" \
  | line.trim.quoted \
  | line.unquote \
  | line select 6
  
  #dscl . -read /Users/marcel | line find Home | line split ":" | line unquote | line select 2
}

private.get.shell.linux() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then shift; fi

  source line 
  private.get.info.linux "$username" \
  | line.split ":" \
  | line.unquote \
  | line select 7
  
  #dscl . -read /Users/marcel | line find Shell | line split ":" | line unquote | line select 2

}

private.get.shell.darwin() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then 
    shift; 
  else
    username=$USER
  fi

  source line 
  dscl . -read /Users/"$username"  \
  | line.find Shell \
  | line.split ":" \
  | line.trim.quoted \
  | line.unquote \
  | line.select 2
}

private.get.home.darwin() # <username> #
{
  local username="$1"
  if [ -n "$1" ]; then
    shift;
  else
    username=$USER
  fi

  source line
  # `dscl . -read /Users/root NFSHomeDirectory` on macOS returns BOTH
  # the user-visible path AND its canonical form for root:
  #   NFSHomeDirectory: /var/root /private/var/root
  # (because /var → /private/var is a macOS system symlink, and the
  # directory service publishes both). Other users return a single
  # path. Filter to the first whitespace-separated token so callers
  # don't end up with `cd "/var/root /private/var/root"` — exactly
  # the bug that broke `config.init.user root` on macOS, surfacing
  # as the `oo update` heal failure on macstudio.
  dscl . -read /Users/"$username"  \
  | line.find Home \
  | line.split ":" \
  | line.trim.quoted \
  | line.unquote \
  | line.select 2 \
  | awk '{print $1}'
}

private.get.info.darwin() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then 
    shift; 
  else
    username=$USER
  fi

  source line 
  dscl . -read /Users/"$username"  
}

user.create()  # <username> <?password> <?uid> <?gid> # creates a new user with home dir and auto-installs oosh. Optional args are keyword-style (password/uid/gid). Default password = username.
{
  local name="$1"
  if [ -n "$1" ]; then
    shift
  else
    error.log "no ${YELLOW}username${NORMAL} was specified"
    return 1
  fi

  local password=""
  local passwordSet=
  local customUid=
  local customGid=
  while [ -n "$1" ]; do
    case "$1" in
      password) shift; password="$1"; passwordSet=1 ;;
      uid)      shift; customUid="$1" ;;
      gid)      shift; customGid="$1" ;;
      *)        warn.log "user.create: ignoring unknown argument '$1' (keywords: password, uid, gid)" ;;
    esac
    shift
  done

  # Default password = username (matches ossh:725 convention; pass 'password ""' to opt out).
  # macOS password policy rejects passwords < 4 chars with
  # "New account password error. (5402)" from sysadminctl, leaving the
  # user half-created. Pad short default passwords deterministically by
  # doubling the username (e.g. "bob" → "bobbob").
  os.check.env
  if [ -z "$passwordSet" ]; then
    password="$name"
    if [ "$OOSH_OS" = "darwin" ] && [ "${#password}" -lt 4 ]; then
      password="$name$name"
      info.log "user.create: default password padded to '$password' to meet macOS min-length policy"
    fi
  fi

  if [ "$OOSH_OS" = "darwin" ]; then
    # macOS: sysadminctl sets the initial password at creation time.
    # Prefer brew bash 4+ over system /bin/bash (3.2) — oosh's init/oosh
    # asserts bash 4+ at this:215-227, so creating a user with bash 3.2
    # makes their first oosh login fail. ossh.prereqs.install ensures
    # brew bash is present before this point in real-world flows.
    local _shell=/bin/bash
    [ -x /opt/homebrew/bin/bash ] && _shell=/opt/homebrew/bin/bash   # Apple Silicon
    [ -x /usr/local/bin/bash ] && _shell=/usr/local/bin/bash         # Intel Mac
    if ! $SUDO sysadminctl -addUser "$name" -password "$password" -shell "$_shell"; then
      error.log "user.create: sysadminctl failed to create '$name' — user likely rejected by password policy or already exists. Aborting."
      return 1
    fi
  else
    # useradd may be in /usr/sbin which is not in PATH on Debian
    local _useradd
    _useradd=$(command -v useradd 2>/dev/null || echo /usr/sbin/useradd)
    if [ -x "$_useradd" ]; then
      # GNU useradd (Debian, Ubuntu, RHEL, AlmaLinux)
      # Use -N (no user private group) if a group with the same name already exists
      local _upg=""
      getent group "$name" >/dev/null 2>&1 && _upg="-N -g $name"
      if [ -n "$customUid" ]; then
        $SUDO "$_useradd" -m $name -u$customUid -g$customGid -s /bin/bash
      else
        $SUDO "$_useradd" -m $_upg $name -s /bin/bash
      fi
    elif command -v adduser >/dev/null 2>&1; then
      # BusyBox adduser (Alpine)
      # Use -G (existing group) if a group with the same name already exists
      local _grp=""
      getent group "$name" >/dev/null 2>&1 && _grp="-G $name"
      if [ -n "$customUid" ]; then
        $SUDO adduser -s /bin/bash -h /home/$name -u $customUid -G $customGid -D $name
      else
        $SUDO adduser -s /bin/bash -h /home/$name $_grp -D $name
      fi
    else
      error.log "Neither useradd, adduser, nor sysadminctl found — cannot create user $name"
      return 1
    fi
  fi

  # Set (or reset) the password via the cross-platform oosh helper.
  # On macOS this also provides a dscl safety-net for admins without a secure token.
  # On Linux this is the one that actually populates /etc/shadow (useradd leaves it locked).
  if [ -n "$password" ]; then
    user.password.set "$name" "$password"
  fi

  # Add to the platform's sudoer group (os-specific — 'wheel' is NOT a sudoer on
  # macOS, so matching it first there would silently leave the new user without
  # sudo). Dispatched via os.check.
  if os.check private.user.create.addSudoer; then
    $RESULT "$name"
  fi
  # Add to dev group if it exists (platform-agnostic shared-workspace group)
  if private.user.check.group dev; then
    user.group.add dev $name
  fi

  # Auto-install oosh for the new user from the creator's current branch.
  # Soft-fail: if the shared infrastructure isn't there (e.g. pre-root-install)
  # the user account is still created; the symlinking step just gets skipped.
  user.oosh.install "$name" || warn.log "user.oosh.install skipped for '$name' — see errors above"

  RETURN=$1
}

user.create.completion.username() {
  user.parameter.completion.username "$@"
}

# Sudoer-group helpers — which group actually grants sudo depends on the OS.
#   macOS           → 'admin' (wheel exists but is NOT a sudoer group)
#   Debian / Ubuntu → 'sudo'
#   RHEL / Alpine   → 'wheel'
# Called from user.create via os.check dispatch.
private.user.create.addSudoer.darwin() # <username> # macOS: add user to 'admin' (the sudoer group)
{
  local username="$1"
  if private.user.check.group admin; then
    user.group.add admin "$username"
  fi
}

private.user.create.addSudoer.linux() # <username> # Linux: prefer 'sudo' (Debian family), fall back to 'wheel' (RHEL/Alpine)
{
  local username="$1"
  if private.user.check.group sudo; then
    user.group.add sudo "$username"
  elif private.user.check.group wheel; then
    user.group.add wheel "$username"
  fi
}

user.create.completion.password() {
  echo "password"
  echo "uid"
  echo "gid"
}

user.create.completion.uid() {
  echo "uid"
  echo "gid"
  echo "password"
}

user.create.completion.gid() {
  echo "gid"
  echo "password"
  echo "uid"
}

user.password.set()        # <username> <password> # sets (or resets) a user's password; dispatches via os.check
{
  local username="$1"
  if [ -n "$1" ]; then
    shift
  else
    error.log "no ${YELLOW}username${NORMAL} was specified"
    return 1
  fi
  local password="$1"
  # password may legitimately be empty; treat as no-op to match old passwordless behaviour
  if [ -z "$password" ]; then
    info.log "user.password.set: empty password for $username — skipping"
    return 0
  fi
  if os.check user.password.set; then
    $RESULT "$username" "$password"
  else
    important.log "$RESULT is not supported"
    return 1
  fi
}

user.password.set.darwin() # <username> <password> # macOS: dscl-based (no secure-token dependency)
{
  $SUDO dscl . -passwd "/Users/$1" "$2"
}

user.password.set.darwin.completion.username() { user.list; }
user.password.set.darwin.completion.password() { :; }

user.password.set.linux() # <username> <password> # Linux (GNU coreutils & BusyBox): chpasswd
{
  echo "$1:$2" | $SUDO chpasswd
}

user.password.set.linux.completion.username() { user.list; }
user.password.set.linux.completion.password() { :; }

user.password.set.completion.username() {
  user.list
}

user.password.set.completion.password() { :; }

# ---------------------------------------------------------------------------
# user.oosh.install — install oosh for a local user from <branch>
#
# Runs the per-user portion of the "shared folder model" introduced by
# ossh.install.user.remote, but LOCALLY (no SSH). Used by user.create so a
# newly-created user inherits the creator's current oosh branch automatically.
#
# Requires the system-level (root) install to have completed already — i.e.
# developking and the shared/ tree must exist. When that's not the case the
# method soft-fails and user.create continues (the user account is still
# created, just without the oosh symlinks).
# ---------------------------------------------------------------------------

private.as.user() # <username> <command...> # run command as <username> — prefers runuser (no sudo needed when root), falls back to sudo -H -u, then su -
{
  # Dispatch order matters — runuser FIRST, sudo SECOND, su THIRD:
  #   1. runuser  — only path that doesn't need sudo at all (root + util-linux).
  #                 Preferred on minimal containers where sudo isn't installed
  #                 yet (e.g. naked Alpine before `apk add sudo`).
  #   2. sudo -H -u — most distros; requires the caller to be a sudoer.
  #                   -H resets HOME so the inner shell uses the target's home.
  #   3. su -s /bin/bash - <user> -c <cmd> — last resort; root-only fallback
  #                   for environments without runuser AND without sudo.
  # Reversing this order would silently break sudo-less containers (sudo
  # branch fails, su needs root, runuser would have worked) and any
  # non-root-but-sudo caller switching to themselves.
  # Verified by T-PRIVATE-AS-USER-DISPATCH in test/test.user.
  local username="$1"; shift
  if [ "$(id -u)" = "0" ] && command -v runuser >/dev/null 2>&1; then
    runuser -u "$username" -- "$@"
  elif command -v sudo >/dev/null 2>&1; then
    sudo -H -u "$username" "$@"
  elif [ "$(id -u)" = "0" ] && command -v su >/dev/null 2>&1; then
    # su -c takes a single string. Re-quote args so they survive the join.
    local _cmd=""
    local _a
    for _a in "$@"; do
      _cmd+="${_cmd:+ }$(printf '%q' "$_a")"
    done
    su -s /bin/bash - "$username" -c "$_cmd"
  else
    error.log "private.as.user: cannot switch to '$username' — need runuser, sudo, or root+su"
    return 127
  fi
}

user.oosh.install() # <username> <?branch:$OOSH_MODE> # installs oosh for a local user from <branch> (defaults to the creator's current oosh branch)
{
  local username="$1"
  if [ -n "$1" ]; then
    shift
  else
    error.log "no ${YELLOW}username${NORMAL} was specified"
    return 1
  fi

  local branch="$1"
  [ -n "$branch" ] && shift
  [ -z "$branch" ] && branch="$OOSH_MODE"
  [ -z "$branch" ] && branch=$(this.git.branch.short "$OOSH_DIR")
  if [ -z "$branch" ]; then
    error.log "user.oosh.install: cannot determine current oosh branch"
    return 1
  fi

  local targetHome devHome baseDir sharedConfig sharedOosh
  targetHome=$(user.get home "$username")
  devHome=$(user.get home developking)
  if [ -z "$targetHome" ]; then
    error.log "user.oosh.install: cannot resolve home for '$username'"
    return 1
  fi
  if [ -z "$devHome" ]; then
    error.log "user.oosh.install: 'developking' user not found — run 'ossh install' (root) first"
    return 1
  fi

  baseDir=$(dirname "$devHome")
  sharedConfig="$baseDir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig"
  sharedOosh="$baseDir/shared/EAMD.ucp/Components/com/ceruleanCircle/EAM/1_infrastructure/Once.sh/$branch"

  # Single-shot existence check — do NOT poll here. user.create (user:576)
  # auto-invokes user.oosh.install for the newly-created user, and state
  # 31's body (oo:1219) runs `user create developking` mid-body BEFORE it
  # creates $sharedOosh (via `git worktree add` at oo:1337). Polling here
  # deadlocks that path: state 31 can't progress until user.create returns,
  # and user.create can't return until user.oosh.install gives up waiting
  # for state 31's own output. user.create soft-fails on our non-zero
  # exit (see user:576 `|| warn.log`), so the proper-order call from
  # install.finish.local finishes the symlink setup after state 31 has
  # completed.
  if [ ! -d "$sharedOosh" ]; then
    info.log "user.oosh.install: $sharedOosh not yet available — skipping symlink setup for '$username' (will be retried once shared oosh exists)"
    return 1
  fi

  important.log "Installing oosh for '$username' from branch '$branch' (shared folder model)"
  info.log "  sharedConfig: $sharedConfig"
  info.log "  sharedOosh:   $sharedOosh"

  # Symlink ~/config and ~/oosh in the target user's home. private.as.user
  # dispatches runuser (root + no sudo needed) / sudo / su, so this works
  # whether the caller is a sudoer, already root on a minimal container
  # without sudo installed, or anything in between.
  local _lnRc=0
  private.as.user "$username" bash -c "
    cd ~
    [ -f ~/oosh ] && [ ! -d ~/oosh ] && rm -f ~/oosh
    [ -d config ] && [ ! -L config ] && mv config config.orig
    [ ! -L config ] && ln -s '$sharedConfig' config
    [ -d oosh ] && [ ! -L oosh ] && mv oosh oosh.orig
    [ ! -L oosh ] && ln -s '$sharedOosh' oosh
  " || _lnRc=$?
  # Verify actual state — macOS sshd + -tt ControlMaster sometimes drops the
  # SSH connection right after the inner commands complete, giving a non-zero
  # client-side exit even when the ln -s commands succeeded on the remote.
  # Check as the target user (same elevation as the creation step): caller
  # may be a non-root sudoer (e.g. bob creating alice) whose traversal of
  # the target's 750-mode home is blocked, which would falsely fail a
  # plain `[ -L /home/alice/config ]` test even when the symlinks exist.
  if private.as.user "$username" test -L "$targetHome/config" \
     && private.as.user "$username" test -L "$targetHome/oosh"; then
    [ "$_lnRc" -ne 0 ] && info.log "user.oosh.install: symlinks for $username are in place (inner shell exited $_lnRc — likely SSH transport hiccup)"
  else
    error.log "user.oosh.install: failed to create ~/config and ~/oosh symlinks for $username"
    return 1
  fi

  # Copy shared SSH dotfiles (user-owned, correct perms).
  # ~/.ssh itself must be 700 and owned by the target user — sshd's
  # StrictModes (default on) refuses authorized_keys under group-writable
  # or wrong-owner .ssh directories. Running via $SUDO means the default
  # umask can be 002 (group-writable), so we tighten perms explicitly.
  # Use `chown <user>:` (trailing colon, no group) so chown sets the group
  # to the user's login group — robust against users whose primary group
  # isn't named the same as the user (e.g. platform.test containers where
  # "test" has gid=0 and no "test" group exists; `chown test:test` errors
  # with "invalid group").
  $SUDO bash -c "
    sharedSsh='$baseDir/shared/.ssh'
    if [ -f \"\$sharedSsh/config\" ]; then
      mkdir -p '$targetHome/.ssh'
      for f in config known_hosts; do
        [ -f \"\$sharedSsh/\$f\" ] && cp \"\$sharedSsh/\$f\" '$targetHome/.ssh/' 2>/dev/null
      done
      chown -R '$username:' '$targetHome/.ssh'
      chmod 700 '$targetHome/.ssh'
      [ -f '$targetHome/.ssh/config' ]      && chmod 600 '$targetHome/.ssh/config'
      [ -f '$targetHome/.ssh/known_hosts' ] && chmod 644 '$targetHome/.ssh/known_hosts'
    fi
  " 2>/dev/null

  # Mark the shared oosh repo as safe (owned by root/developking, read by the new user).
  # macOS HFS+ is case-insensitive but git's safe.directory is a string match —
  # /Users/shared and /Users/Shared are the same inode but different strings.
  # Add the as-computed path AND the canonical-case path via osascript on darwin.
  private.as.user "$username" git config --global --add safe.directory "$sharedOosh" 2>/dev/null
  if command -v osascript >/dev/null 2>&1; then
    local canonicalOosh
    canonicalOosh=$(osascript -e "POSIX path of (POSIX file \"$sharedOosh\" as alias)" 2>/dev/null | sed 's:/$::')
    if [ -n "$canonicalOosh" ] && [ "$canonicalOosh" != "$sharedOosh" ]; then
      private.as.user "$username" git config --global --add safe.directory "$canonicalOosh" 2>/dev/null
    fi
  fi

  # Install bashrcTemplate (or append source line), ensure .bash_profile
  private.as.user "$username" bash -c "
    [ -f ~/.bashrc ] && [ ! -f ~/.bashrc.pre-oosh ] && cp ~/.bashrc ~/.bashrc.pre-oosh
    if [ -f ~/oosh/templates/user/bashrcTemplate ]; then
      cp ~/oosh/templates/user/bashrcTemplate ~/.bashrc
    elif ! grep -q 'config/user.env' ~/.bashrc 2>/dev/null; then
      printf '\n# oosh environment\n[ -f ~/config/user.env ] && source ~/config/user.env\n' >> ~/.bashrc
    fi
    [ ! -f ~/.bash_profile ] && echo '[ -f ~/.bashrc ] && source ~/.bashrc' > ~/.bash_profile
  "

  # Ensure the user is in the shared-folder 'dev' group — the sharedConfig
  # tree is drwxrwsr-x developking:dev, so anything oosh writes there
  # (log.live.out, state files, etc.) needs dev-group write access.
  # user.create adds this already; this second call is idempotent and covers
  # users who came in via ossh.install.user.remote without user.create
  # (e.g. raw-created with sysadminctl).
  if private.user.check.group dev; then
    user.group.add dev "$username"
  fi

  # Write the WODA Host aliases into the target user's ~/.ssh/config.
  # user.init is the canonical writer of WODA Host aliases for non-developking
  # users (user:258-278 — append-if-missing per Host header). Without this
  # invocation here, test/oosh-user/bash-user only ever get the 2cuGitHub
  # alias propagated by private.ossh.shared.ssh.copy.to.all — never WODA.
  # test/test.ssh.config.woda fails for those users without this block.
  #
  # Why a $sharedOosh-rooted source instead of `bash -lc 'user init'`:
  # bashrcTemplate (templates/user/bashrcTemplate:27-30) early-returns for
  # non-interactive shells before its PATH/OOSH setup, so `user` isn't on
  # PATH inside `bash -lc`. Sourcing `\$sharedOosh/this` directly bypasses
  # the early-return and gets oosh's dispatcher in scope.
  #
  # Why HOME/USER reset + CONFIG_* unset: private.as.user prefers
  # `runuser -u <user> --` (user:711-712) which does NOT reset HOME — the
  # caller's env leaks through. Without the explicit reset, \$HOME stays
  # /root and \$CONFIG_PATH from a prior config.init resolves to /root/config
  # — c2's staging file lands in /root/config/result.txt and reads-back
  # fail with Permission denied for the target user.
  #
  # IMPORTANT — does NOT damage sharedConfig (post-c10def5): the chown -h
  # in private.ossh.push.config preserves sharedConfig ownership; this
  # `user init` only writes to \$sshDir/config (~/.ssh/config), not to
  # ~/config. c2 dispatch may write through ~/config to sharedConfig but
  # only as the target user via dev-group writes (mode g+w preserved).
  private.as.user "$username" bash -c "
    export HOME='$targetHome'
    export USER='$username'
    unset CONFIG CONFIG_PATH CONFIG_FILE
    cd \"\$HOME\" 2>/dev/null
    source '$sharedOosh/this' >/dev/null 2>&1 || exit 1
    user init
  " || warn.log "user.oosh.install: 'user init' for $username did not complete cleanly — WODA aliases may be missing from $targetHome/.ssh/config"

  # Materialize the canonical ~/.ssh layout for this user — `ids/` subtree
  # with ssh.developking + ssh.<installer-id> + ssh.outeruser, plus the
  # private_key/<id>-> ../id_ed25519 and public_keys/<id>->../id_ed25519.pub
  # symlinks. Without this, non-root users (test, oosh-user, bash-user in
  # os.platform.test) only get a bare keypair + 2cuGitHub — root has the
  # full layout (osshLayout build is invoked for root at ossh:691, but the
  # per-user invocation was dropped by d9adb27 alongside band-aids).
  # test/test.platform.ssh.layout.invariant pins the invariant.
  #
  # $SUDO bash -c so writes succeed even when the caller can't write into
  # the target user's $HOME (e.g. test creating oosh-user via the platform
  # test pipeline). osshLayout creates files as root because it runs under
  # $SUDO, then we chown the entire .ssh tree to the target user. Safe
  # because Phase 2 of the .ssh/ correctness plan replaced all symlinks
  # under ids/ with real-file copies — chown -R follows symlinks but
  # there are none anymore (verified by test.osshLayout's no-symlink
  # assertions and test.platform.ssh.layout.invariant). Without this
  # chown, ~/.ssh/ids/ is owned by root with mode 700 and the user can't
  # even read their own developking key for github auth.
  local _ownerEmail
  _ownerEmail=$(private.as.user "$username" git config user.email 2>/dev/null) || true
  [ -z "$_ownerEmail" ] && _ownerEmail="${username}@$(hostname)"
  $SUDO bash -c "
    export OOSH_DIR='$sharedOosh'
    export PATH=\"\$OOSH_DIR:\$PATH\"
    USER_EMAIL='$_ownerEmail' '$sharedOosh/osshLayout' build '' '' '$targetHome/.ssh'
    chown -R '$username:' '$targetHome/.ssh'
  " || warn.log "osshLayout build for '$username' did not complete cleanly — ~/.ssh/ids/ may be incomplete"

  # Platform-specific login-shell + SSH/docker group membership, dispatched via os.check
  if os.check private.user.oosh.install.shell; then
    $RESULT "$username" "$targetHome"
  fi
  if os.check private.user.oosh.install.groups; then
    $RESULT "$username"
  fi

  # Defensive sweep: a symlink inside $sharedOosh whose name matches a sibling
  # worktree (or this worktree itself) turns `git log <branch>` into
  # "ambiguous argument: both revision and filename" because git treats the
  # bare branch name as a pathspec. Nothing in oosh references
  # $sharedOosh/<branchname>; remove any such link regardless of who made it.
  # (Observed intermittently; root creator not yet traced after multiple runs.)
  local worktreeBase
  worktreeBase=$(dirname "$sharedOosh")
  if [ -d "$worktreeBase" ]; then
    local wtName
    for wtName in "$worktreeBase"/*/; do
      wtName=$(basename "${wtName%/}")
      [ -L "$sharedOosh/$wtName" ] || continue
      warn.log "Removing stray symlink '$sharedOosh/$wtName' (shadows branch name)"
      sudo rm -f "$sharedOosh/$wtName"
    done
  fi

  important.log "✓ oosh installed for '$username' from branch '$branch'"
}

user.oosh.install.completion.username() { user.list; }
user.oosh.install.completion.branch() {
  [ -n "$OOSH_DIR" ] && ls "$(dirname "$OOSH_DIR")" 2>/dev/null
}

private.user.oosh.install.shell.darwin() # <username> <targetHome> # ensures bash is the login shell on macOS via dscl (chsh silently fails for sysadminctl/OD-managed users)
{
  local username="$1"
  local targetHome="$2"
  local bashPath currentShell
  if [ -f "$targetHome/config/user.env" ]; then
    bashPath=$(grep '^export BASH_FILE=' "$targetHome/config/user.env" | head -1 | cut -d'"' -f2)
  fi
  [ -z "$bashPath" ] && bashPath=$(command -v bash 2>/dev/null)
  currentShell=$(dscl . -read "/Users/$username" UserShell 2>/dev/null | awk '{print $2}')

  if [ -z "$bashPath" ] || [ "$currentShell" = "$bashPath" ]; then
    return 0
  fi

  # macOS-native: `dscl . -change /Users/<user> UserShell <old> <new>` writes
  # the Open Directory record directly. `chsh -s` is the historical Unix way
  # but on macOS it requires (a) the target shell listed in /etc/shells —
  # /opt/homebrew/bin/bash typically isn't there — and (b) the user's own
  # password OR full superuser context, which sudo+chsh doesn't always
  # provide for sysadminctl-created users. dscl skips both gates.
  if $SUDO dscl . -change "/Users/$username" UserShell "$currentShell" "$bashPath" 2>/dev/null; then
    success.log "user shell for $username switched: $currentShell → $bashPath (dscl)"
    return 0
  fi

  # Fallback for the rare environment where dscl isn't usable as root —
  # e.g. some hardened MDM-managed Macs reject -change without GUI auth.
  # Try chsh; if /etc/shells doesn't list bashPath yet, append first.
  if [ -w /etc/shells ] || $SUDO test -w /etc/shells 2>/dev/null; then
    grep -qxF "$bashPath" /etc/shells 2>/dev/null \
      || $SUDO bash -c "echo '$bashPath' >> /etc/shells" 2>/dev/null
  fi
  if $SUDO chsh -s "$bashPath" "$username" 2>/dev/null; then
    success.log "user shell for $username switched: $currentShell → $bashPath (chsh)"
    return 0
  fi

  warn.log "Could not change $username's login shell to bash — neither dscl nor chsh succeeded; ssh-cat oosh commands may fail in zsh"
  return 1
}

private.user.oosh.install.shell.linux() # <username> <targetHome> # ensures bash is the login shell on Linux (incl. BusyBox/Alpine)
{
  local username="$1"
  local bashPath currentShell
  bashPath=$(command -v bash 2>/dev/null)
  currentShell=$(getent passwd "$username" 2>/dev/null | cut -d: -f7)
  if [ -n "$bashPath" ] && [ "$currentShell" != "$bashPath" ]; then
    if command -v chsh >/dev/null 2>&1; then
      $SUDO chsh -s "$bashPath" "$username" 2>/dev/null
    else
      $SUDO sed -i "s|^$username:\(.*\):[^:]*\$|$username:\1:$bashPath|" /etc/passwd
    fi
  fi
}

private.user.oosh.install.groups.darwin() # <username> # macOS group memberships needed for SSH login and docker
{
  local username="$1"
  # com.apple.access_ssh is a restriction group: once it EXISTS on macOS, only
  # its members can SSH in. Creating it from scratch with only one member
  # locks every other user out. So: only add <username> if the group already
  # exists. If it doesn't exist yet, SSH is open — leave that policy alone.
  if dscl . -read /Groups/com.apple.access_ssh >/dev/null 2>&1; then
    $SUDO dseditgroup -o edit -a "$username" -t user com.apple.access_ssh 2>/dev/null
  fi
  if command -v docker >/dev/null 2>&1; then
    $SUDO dseditgroup -o edit -a "$username" -t user docker 2>/dev/null
  fi
}

private.user.oosh.install.groups.linux() # <username> # Linux group memberships (docker if available)
{
  local username="$1"
  if command -v docker >/dev/null 2>&1; then
    user.group.add docker "$username" 2>/dev/null
  fi
}

user.linux.delete() { # <username> # removes the user and all its files
  private.user.delete.linux "$@"
}

private.user.delete.linux() { # <username> # removes the user and all its files
  local username="$1"
  if [ -n "$1" ]; then shift; fi
  os.check.env
  if [ "$OOSH_OS" = "darwin" ]; then
    $SUDO sysadminctl -deleteUser "$username"
  else
    # userdel may be in /usr/sbin which is not in PATH on Debian
    local _userdel
    _userdel=$(command -v userdel 2>/dev/null || echo /usr/sbin/userdel)
    $SUDO "$_userdel" -rf $username
  fi
}

# duplicat
# user.check.group() {
#   local group=$1
#   shift 
#   if [ $(getent group admin) ]; then
#     create.result 0 "group $group exists" "$1"
#   else
#     create.result 1 "group $group does not exist"  "$1"
#   fi
#   echo "$RESULT"
#   return "$(result)"
# }

user.list() {
  user.list.all "$1" | line filter "^_"
}

user.list.all() {
  compgen -u "$1"
}

user.list.other.identities() { # <?sshDir:~/.ssh> # lists identities in <sshDir>/ids
  private.user.get.sshDir "$1"
  ls $RESULT/ids
}

user.get.current.identity() { # # shows the current SSH identity directory
  private.user.get.sshDir
  echo "$RESULT"
}

user.list.groups() {
  compgen -g "$1"
}

user.login() # <userName> # switch to userName via login shell — cd to target home and reset env
{
  # `su -` (login shell) — without it, su keeps the caller's cwd and PATH,
  # so e.g. `user login alice` from /home/bob lands alice in /home/bob
  # which she can't even read (drwxr-x--- bob:bob). A login shell runs
  # alice's .profile/.bashrc, cds to ~alice, and resets HOME/USER/etc.
  env -i su - "$1"
}

user.group.add() # <groupName> <?toUsername> # adds <toUsername> to group <groupName> if both exist
{

  local groupName="$1"
  if [ -n "$1" ]; then
    groupName="$1"
    shift
  else
    error.log "no ${YELLOW}groupName${RED} was specified"
    return 1
  fi 

  local toUsername="$1"
  if [ -n "$1" ]; then
    toUsername="$1"
    shift
  else
    console.log "no ${YELLOW}toUsername${NORMAL} was specified"
  fi 

  os.check.env
  if private.user.check.group "$groupName"; then
    info.log "groupName already exists: $groupName"
  else
    if [ "$OOSH_OS" = "darwin" ]; then
      $SUDO dseditgroup -o create -q "$groupName" 2>/dev/null
    else
      console.log "creating groupName: $OS_CMD_GROUP_ADD $groupName"
      $SUDO $OS_CMD_GROUP_ADD $groupName
    fi
  fi

  if [ -n "$toUsername" ]; then
    if [ "$OOSH_OS" = "darwin" ]; then
      # macOS: use dseditgroup for group membership
      $SUDO dseditgroup -o edit -a "$toUsername" -t user "$groupName" 2>/dev/null
    elif [ "$OS_CMD_USER_MOD" = "addgroup" ]; then
      # Alpine: addgroup <user> <group> (reversed order)
      $SUDO $OS_CMD_USER_MOD "$toUsername" "$groupName"
    else
      $SUDO $OS_CMD_USER_MOD "$groupName" "$toUsername"
    fi
  fi
}

user.group.add.completion.groupName() {
  user.list.groups "$@"
}
user.group.add.completion.toUsername() {
  user.parameter.completion.username "$@"
}

user.group.check() # <groupName> # checks if a group exists
{
  private.user.check.group "$@"
}

private.user.check.group() # <groupName> # checks if a group exists
{
  os.check.env
  if [ "$OOSH_OS" = "darwin" ]; then
    # macOS: use dscl to check group existence
    if dscl . -read /Groups/"$1" &>/dev/null; then
      success.log "group exists: $1"
      return 0
    else
      warn.log "group does ${RED}NOT${YELLOW} exist: ${RED}$1${NORMAL}"
      return 1
    fi
  fi
  source line
  local result=$( compgen -g "$1" | line.format "%s:" | line.find "$1:" | line.count )
  if this.isNumber "$result"; then
    if [ $result -eq 1 ];then
      success.log "group exists: $1"
      return 0
    else
      if [ $result -eq 0 ];then
            warn.log  "group does ${RED}NOT${YELLOW} exist: ${RED}$1${NORMAL}"
            compgen -g "$1"
            return 1
      fi
      warn.log "multiple groups exist: $1"
      compgen -g "$1"
      return 0
    fi
  else
    warn.log "reult: $result"
    return 1
  fi
}

user.ssh.backup() {
  local name="$1"
  if [ -z "$name" ]; then
    name="bak"
  fi
  if [ -n "$1" ]; then
    shift
  fi

  private.user.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  cp -R $sshDir ssh.$name 
}

user.ssh.restore() {
  local name="$1"
  if [ -z "$name" ]; then
    name="bak"
  fi
  if [ -n "$1" ]; then
    shift
  fi

  private.user.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  rm -Rf $sshDir 
  cp -R ssh.$name $sshDir 
}

user.usage()
{
  local this=${0##*/}
  echo "You started 
$0
  
  Usage:
  $this: command   description and Parameter

      usage                   prints this dialog while it will print the status when there are no parameters          
      v                       print version information

      in 
  
      list  
      create                  <username> [keyword args: password, uid, gid]  — creates a new user with home dir, sets the password, and auto-installs oosh from the creator's branch.
      password.set            <username> <password>  — sets/resets a user's password cross-platform
      oosh.install            <username> [<branch>]  — installs oosh for an existing local user from <branch> (defaults to creator's \$OOSH_MODE)
      authorized.keys.update  <?sshDir:\"~/.ssh\">
  
      ssh.status log          logs if ther is an ssh config
      ssh.init                creates a new ssh config
  
      ssh.rename.files        <newName> <?sshDir:\"~/.ssh\">
      ssh.get.key.name      
      ssh.get.file.name       <?sshDir:\"~/.ssh\">

      ssh.backup              <newName> <?sshDir:\"~/.ssh\"> will result in a ssh.newName folder
      ssh.restore             <newName> <?sshDir:\"~/.ssh\"> CAREFULL!!! ssh.newName in sshDir and if not present overwites the current .ssh folder

      ssh.rootkey.file.revoke <sshConfigName> <publicKeyFile>      revokes access for the public key file
      ssh.rootkey.file.push   <sshConfigName> <publicKeyFile>      pushes the public key file        to the root of the specified ssh server and makes it authorized
      ssh.rootkey.push        <sshConfigName> <?sshDir:\"~/.ssh\"> pushes the public key from sshDir to the root of the specified ssh server and makes it authorized
      ssh.rootkey.pull        <sshConfigName> gets the root public key of the specified ssh server
      ----      --------------------------"
  this.help
  echo "
  ${NO_COLOR}
  Examples
    user init
    
    user in ./KPP/ssh.developer ssh.get.file.name
    user ssh.get.file.name ./KPP/ssh.developer

  OS details:
      OS_CMD_USER_ADD=$OS_CMD_USER_ADD
      OS_CMD_USER_MDO=$OS_CMD_USER_MOD  
      OS_CMD_USER_DEL=$OS_CMD_USER_DEL
      OS_CMD_GROUP_ADD=$OS_CMD_GROUP_ADD
  "
}

private.user.init() {
  if [ -z "$USER" ]; then
    USER=$(id -u -n)
  fi
  ONCE_SUDO=sudo

  # Load the cached OS_CMD_* vars if we have them. We source unconditionally
  # when the file exists, then self-heal below if any are missing — this
  # survives an incomplete cache (e.g. private.check.pm at oo:~1848 saves
  # os.commands.env during install before private.user.init has computed
  # OS_CMD_USER_MOD / OS_CMD_USER_DEL, leaving the cache with only 2 of 4
  # vars; without the self-heal, user.group.add at user:1018 silently
  # degraded to `sudo "" <group> <user>` → "bash: <group>: command not
  # found", and new users never joined the `dev` group).
  if [ -f $CONFIG_PATH/os.commands.env ]; then
    source $CONFIG_PATH/os.commands.env
  fi

  if [ -z "$OS_CMD_USER_ADD" ] || [ -z "$OS_CMD_USER_DEL" ] \
     || [ -z "$OS_CMD_USER_MOD" ] || [ -z "$OS_CMD_GROUP_ADD" ]; then
    os.check.env
    if [ "$OOSH_OS" = "darwin" ]; then
      [ -z "$OS_CMD_USER_ADD"  ] && export OS_CMD_USER_ADD="sysadminctl -addUser"
      [ -z "$OS_CMD_USER_DEL"  ] && export OS_CMD_USER_DEL="sysadminctl -deleteUser"
      [ -z "$OS_CMD_USER_MOD"  ] && export OS_CMD_USER_MOD="dseditgroup -o edit -a"
      [ -z "$OS_CMD_GROUP_ADD" ] && export OS_CMD_GROUP_ADD="dseditgroup -o create -q"
    else
      # Linux: discover sbin tools (may not be in PATH on Debian). Only
      # set vars that weren't already loaded from the cache.
      if [ -z "$OS_CMD_USER_ADD" ]; then
        if [ -x "$(command -v adduser 2>/dev/null)" ]; then
          export OS_CMD_USER_ADD="adduser"
        fi
        local _useradd
        _useradd=$(command -v useradd 2>/dev/null || echo /usr/sbin/useradd)
        if [ -x "$_useradd" ]; then
          export OS_CMD_USER_ADD="$_useradd"
        fi
      fi
      if [ -z "$OS_CMD_USER_DEL" ]; then
        local _userdel
        _userdel=$(command -v userdel 2>/dev/null || echo /usr/sbin/userdel)
        if [ -x "$_userdel" ]; then
          export OS_CMD_USER_DEL="$_userdel"
        fi
      fi
      if [ -z "$OS_CMD_USER_MOD" ]; then
        local _usermod
        _usermod=$(command -v usermod 2>/dev/null || echo /usr/sbin/usermod)
        if [ -x "$_usermod" ]; then
          export OS_CMD_USER_MOD="$_usermod -a -G"
        elif [ -x "$(command -v addgroup 2>/dev/null)" ]; then
          export OS_CMD_USER_MOD="addgroup"
        fi
      fi
      if [ -z "$OS_CMD_GROUP_ADD" ]; then
        if [ -x "$(command -v addgroup 2>/dev/null)" ]; then
          export OS_CMD_GROUP_ADD="addgroup"
        fi
        local _groupadd
        _groupadd=$(command -v groupadd 2>/dev/null || echo /usr/sbin/groupadd)
        if [ -x "$_groupadd" ]; then
          export OS_CMD_GROUP_ADD="$_groupadd"
        fi
      fi
    fi
    # Persist the complete set so future sessions hit a healthy cache.
    # Silence chatter twice:
    #   (a) stdout via `>/dev/null 2>&1` — needed for $(user get basehome)
    #       and similar captured contexts during state 31's
    #       private.install.dev.configs; without it, config.save's
    #       `echo "config.save (CONFIG=...)"` (config:496 IS plain
    #       stdout, not log.*) would propagate a garbage IdentityFile
    #       into the generated 2cuGitHub config block and fail the
    #       downstream git clone.
    #   (b) log device — `console.log` / `important.log` write to
    #       $LOG_DEVICE (typically a tty), bypassing the `>/dev/null`
    #       on the function call. Visible as "OOSH_PM: apk add",
    #       "IMPORTANT> generating …user.env", "IMPORTANT> new
    #       LOG_DEVICE=…", "IMPORTANT> this.load: save config" — the
    #       full cascade from oo.pm.discover's internal `config save`
    #       (no args) → config:601's `log.device $LOG_DEVICE` HACK →
    #       recursive `this.call config save log LOG`.
    #       Side-effect-free because config.save filters out
    #       LOG_DEVICE from log.env persistence (config:547
    #       `grep -v 'LOG_DEVICE='`), so the temporary /dev/null
    #       swap doesn't leak into the saved env files.
    local _origLogDevice="${LOG_DEVICE:-/dev/tty}"
    export LOG_DEVICE=/dev/null
    config save os.commands "OS_CMD" >/dev/null 2>&1
    oo pm.discover                   >/dev/null 2>&1
    export LOG_DEVICE="$_origLogDevice"
  fi
}

user.start()
{
  #echo "sourcing init"
  source this
  source ossh
  source os
  private.user.init

  # if [ -z "$1" ]; then
  #   status.discover "$@"
  #   return 0
  # fi

  this.start "$@"
}

user.start "$@"

