Viktor asked to restructure Anca's setup: her ~/code WAS the infra clone itself; he wants ~/code to be the directory where all her project repos (tripit etc.) live side by side, with infra moved to a subdirectory. - roster.yaml gains per-user 'code_layout: single|workspace' + 'repos', validated + derived by roster_engine.py (12 new tests, 40 total). - t3-provision-users reconcile: auto-migrates a single-layout ~/code to ~/code/infra (running processes follow the moved inode), hoists nested project clones to the workspace root, clones roster repos from Forgejo AS the user (their PAT makes private repos work), and wires the documented forgejo remote + forgejo/master upstream into clones that predate that contract. - Fixed a latent TSV bug: empty jq @tsv fields collapse under tab-IFS read, shifting later fields left (groups was only safe by being the last field) — emit '-' sentinels instead. - start-claude.sh session freshen is layout-aware (freshens each repo under ~/code for workspace users). - managed claudeMd + AGENTS.md non-admin recipe + multi-tenancy.md updated in the same change. Applied live: ancamilea = workspace (infra at ~/code/infra, her existing tripit clone hoisted to ~/code/tripit, master upstream switched to forgejo/master); emo stays single layout, untouched. [ci skip]
65 lines
2.6 KiB
Bash
Executable file
65 lines
2.6 KiB
Bash
Executable file
#!/bin/bash
|
|
# Per-user Claude Code Workstation launcher (devvm). Lands the user in their OWN
|
|
# ~/code clone (NOT a hardcoded /home/wizard/code) and names the Claude session
|
|
# after the tmux session so /resume, the prompt box, and the terminal title line
|
|
# up. Deployed via /etc/skel by setup-devvm.sh, so new accounts get it on
|
|
# `useradd -m`. Existing users are repointed to this during their migration.
|
|
echo ""
|
|
echo " Welcome, $(id -un)! 🚀"
|
|
echo ""
|
|
echo " Starting Claude Code in $HOME/code ..."
|
|
echo " (Right-click for tmux menu, or Ctrl+B then | or - to split)"
|
|
echo ""
|
|
|
|
name_args=()
|
|
if [ -n "${TMUX:-}" ]; then
|
|
sess="$(tmux display-message -p '#{session_name}' 2>/dev/null)"
|
|
[ -n "$sess" ] && name_args=(--name "$sess")
|
|
fi
|
|
|
|
cd "$HOME/code" 2>/dev/null || cd "$HOME"
|
|
|
|
# Freshen the user's clone(s) at session start so they begin on current upstream
|
|
# state (the hourly t3-provision-users reconcile does the same in the background).
|
|
# Single layout freshens ~/code itself; workspace layout freshens each repo under
|
|
# ~/code. Fast-forward only, and only when safe (on master + clean tree); hard
|
|
# 10s fetch cap per repo so an offline remote never stalls the launch.
|
|
freshen_repo() {
|
|
GIT_TERMINAL_PROMPT=0 timeout 10 git -C "$1" fetch --all --prune --quiet 2>/dev/null || true
|
|
if [ "$(git -C "$1" symbolic-ref --short -q HEAD)" = master ] \
|
|
&& [ -z "$(git -C "$1" status --porcelain 2>/dev/null)" ] \
|
|
&& git -C "$1" rev-parse --verify -q 'master@{upstream}' >/dev/null 2>&1; then
|
|
git -C "$1" merge --ff-only 'master@{upstream}' >/dev/null 2>&1 || true
|
|
fi
|
|
}
|
|
if [ -d "$HOME/code/.git" ]; then
|
|
freshen_repo "$HOME/code"
|
|
else
|
|
for repo_git in "$HOME"/code/*/.git; do
|
|
[ -d "$repo_git" ] && freshen_repo "${repo_git%/.git}"
|
|
done
|
|
fi
|
|
|
|
# Prefer the system-wide `claude` (installed by setup-devvm.sh); fall back to npx.
|
|
launch() {
|
|
if command -v claude >/dev/null 2>&1; then
|
|
claude "$@"
|
|
else
|
|
npx @anthropic-ai/claude-code "$@"
|
|
fi
|
|
}
|
|
|
|
# Deliberately not `exec` so we can branch on the exit code: clean quit ends the
|
|
# pane (ttyd closes the terminal); a crash drops to a shell so the tmux session
|
|
# isn't destroyed-and-recreated in a ttyd auto-reconnect loop.
|
|
# No --model flag: inherit the org-wide default from /etc/claude-code/managed-settings.json
|
|
# (an explicit --model would override that managed default for every launched session).
|
|
launch --dangerously-skip-permissions "${name_args[@]}"
|
|
code=$?
|
|
[ "$code" -eq 0 ] && exit 0
|
|
|
|
echo ""
|
|
echo " claude exited abnormally (status $code). Dropping to a shell — your tmux session is preserved."
|
|
echo " Re-launch any time with: ~/start-claude.sh"
|
|
echo ""
|
|
exec "${SHELL:-/bin/bash}" -l
|