3030 echo ' {}' > /root/.docker-container/config.json
3131fi
3232
33+ # Download bash-preexec if it doesn't exist (required for atuin/starship)
34+ if [ ! -f ~ /.bash-preexec.sh ]; then
35+ echo " Downloading bash-preexec..."
36+ curl -sL https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~ /.bash-preexec.sh
37+ fi
38+
3339# Initialize bashrc if needed
3440if [ ! -f ~ /.bashrc ] || [ ! -s ~ /.bashrc ] || ! grep -q ' common-bashrc' ~ /.bashrc; then
3541 echo " Initializing ~/.bashrc..."
@@ -59,11 +65,13 @@ if [ -n "$DOCKER_SOCKET_PROXY" ]; then
5965fi
6066
6167# Source common bash configuration (aliases and functions)
62- source /workspace/dev-scripts/common-bashrc.sh
68+ if [ -f /usr/local/share/dev-scripts/common-bashrc.sh ]; then
69+ source /usr/local/share/dev-scripts/common-bashrc.sh
70+ fi
6371
6472# Source the virtual environment (must use source, not bash)
65- if [ -f /workspace /dev-scripts/use-venv ]; then
66- source /workspace /dev-scripts/use-venv
73+ if [ -f /usr/local/share /dev-scripts/use-venv ]; then
74+ source /usr/local/share /dev-scripts/use-venv
6775fi
6876
6977# Load bash-preexec (required for atuin and starship to work with VS Code)
@@ -84,19 +92,26 @@ if command -v starship &> /dev/null; then
8492 eval "$(starship init bash)"
8593fi
8694
87- # Fix for VS Code shell integration overriding PROMPT_COMMAND
88- # Ensure bash-preexec hooks are called so atuin and starship work
89- if declare -F __bp_precmd_invoke_cmd &>/dev/null; then
90- # Prepend bash-preexec to PROMPT_COMMAND if not already there
91- if [[ "$PROMPT_COMMAND" != *"__bp_precmd_invoke_cmd"* ]]; then
92- PROMPT_COMMAND="__bp_precmd_invoke_cmd; $PROMPT_COMMAND"
95+ # Fix for VS Code shell integration overriding bash-preexec's DEBUG trap
96+ # VS Code loads its shell integration after bashrc, so we restore the trap on each prompt
97+ __restore_bash_preexec_trap() {
98+ if declare -F __bp_preexec_invoke_exec &>/dev/null; then
99+ local current_trap=\$(trap -p DEBUG)
100+ if [[ "\$current_trap" != *"__bp_preexec_invoke_exec"* ]]; then
101+ trap '__bp_preexec_invoke_exec "\$_"' DEBUG
102+ fi
93103 fi
104+ }
105+
106+ # Add the trap restoration to PROMPT_COMMAND
107+ if [[ "\$PROMPT_COMMAND" != *"__restore_bash_preexec_trap"* ]]; then
108+ PROMPT_COMMAND="__restore_bash_preexec_trap\${PROMPT_COMMAND:+; \$PROMPT_COMMAND}"
94109fi
95110
96111# asdf version manager
97- if [ -f "$HOME/.asdf/asdf.sh" ]; then
98- . "$HOME/.asdf/asdf.sh"
99- . "$HOME/.asdf/completions/asdf.bash"
112+ if [ -f "\ $HOME/.asdf/asdf.sh" ]; then
113+ . "\ $HOME/.asdf/asdf.sh"
114+ . "\ $HOME/.asdf/completions/asdf.bash"
100115fi
101116EOF
102117fi
@@ -108,8 +123,9 @@ if command -v atuin &> /dev/null; then
108123 # Create atuin data directory if it doesn't exist
109124 mkdir -p ~ /.local/share/atuin ~ /.config/atuin
110125
111- # Generate default config with explicit paths
112- cat > ~ /.config/atuin/config.toml << 'ATUINCONF '
126+ # Generate default config with explicit paths (only if it doesn't exist)
127+ if [ ! -f ~ /.config/atuin/config.toml ]; then
128+ cat > ~ /.config/atuin/config.toml << 'ATUINCONF '
113129## Atuin configuration for CloudHarness dev container
114130
115131## Explicitly set paths to avoid VS Code XDG_DATA_HOME issues
@@ -132,6 +148,7 @@ secrets_filter = true
132148enter_accept = true
133149history_filter = ["^secret", "^password", "AWS_SECRET", "KUBECONFIG"]
134150ATUINCONF
151+ fi
135152
136153 # Import existing bash history
137154 if [ -f ~ /.bash_history ]; then
@@ -140,6 +157,132 @@ ATUINCONF
140157 fi
141158fi
142159
160+ # Create Starship config if it doesn't exist
161+ if [ ! -f ~ /.config/starship.toml ]; then
162+ echo " Creating Starship prompt configuration..."
163+ mkdir -p ~ /.config
164+ cat > ~ /.config/starship.toml << 'STARSHIPCONF '
165+ # Starship prompt configuration for CloudHarness dev container
166+ # Documentation: https://starship.rs/config/
167+
168+ # Timeout for starship to run (in milliseconds)
169+ command_timeout = 1000
170+
171+ # Add a new line before the prompt
172+ add_newline = true
173+
174+ # Format of the prompt
175+ format = """
176+ [╭─](bold green)$username\
177+ $hostname\
178+ $directory\
179+ $git_branch\
180+ $git_status\
181+ $python\
182+ $nodejs\
183+ $docker_context\
184+ $kubernetes
185+ [╰─](bold green)$character"""
186+
187+ [character]
188+ success_symbol = "[➜](bold green)"
189+ error_symbol = "[✗](bold red)"
190+
191+ [username]
192+ style_user = "bold yellow"
193+ style_root = "bold red"
194+ format = "[$user]($style) "
195+ disabled = false
196+ show_always = true
197+
198+ [hostname]
199+ ssh_only = false
200+ format = "[@$hostname](bold blue) "
201+ disabled = false
202+
203+ [directory]
204+ truncation_length = 3
205+ truncate_to_repo = true
206+ format = "[$path]($style)[$read_only]($read_only_style) "
207+ style = "bold cyan"
208+ read_only = " 🔒"
209+
210+ [git_branch]
211+ symbol = " "
212+ format = "on [$symbol$branch]($style) "
213+ style = "bold purple"
214+
215+ [git_status]
216+ format = '([\[$all_status$ahead_behind\]]($style) )'
217+ style = "bold red"
218+ conflicted = "🏳"
219+ ahead = "⇡${count}"
220+ behind = "⇣${count}"
221+ diverged = "⇕⇡${ahead_count}⇣${behind_count}"
222+ untracked = "?${count}"
223+ stashed = "$${count}"
224+ modified = "!${count}"
225+ staged = "+${count}"
226+ renamed = "»${count}"
227+ deleted = "✘${count}"
228+
229+ [python]
230+ symbol = " "
231+ format = 'via [${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) )]($style)'
232+ style = "yellow"
233+ pyenv_version_name = false
234+ detect_extensions = ["py"]
235+ detect_files = [".python-version", "Pipfile", "__pycache__", "pyproject.toml", "requirements.txt", "setup.py", "tox.ini"]
236+ detect_folders = []
237+
238+ [nodejs]
239+ symbol = " "
240+ format = "via [$symbol($version )]($style)"
241+ style = "bold green"
242+
243+ [docker_context]
244+ symbol = " "
245+ format = "via [$symbol$context]($style) "
246+ style = "blue bold"
247+ only_with_files = true
248+ detect_files = ["docker-compose.yml", "docker-compose.yaml", "Dockerfile"]
249+ detect_folders = []
250+
251+ [kubernetes]
252+ symbol = "☸ "
253+ format = 'on [$symbol$context( \($namespace\))]($style) '
254+ style = "cyan bold"
255+ disabled = false
256+ detect_files = ["k8s"]
257+ detect_folders = ["k8s"]
258+
259+ [kubernetes.context_aliases]
260+ "docker-desktop" = "🐳 desktop"
261+ "kind-.*" = "kind"
262+ "minikube" = "mini"
263+
264+ [cmd_duration]
265+ min_time = 500
266+ format = "took [$duration](bold yellow) "
267+
268+ [time]
269+ disabled = false
270+ format = '🕙[\[ $time \]]($style) '
271+ time_format = "%T"
272+ style = "bold white"
273+
274+ [memory_usage]
275+ disabled = true
276+ threshold = -1
277+ symbol = " "
278+ format = "via $symbol[${ram_pct}]($style) "
279+ style = "bold dimmed white"
280+
281+ [package]
282+ disabled = true
283+ STARSHIPCONF
284+ fi
285+
143286# Create tmux config if it doesn't exist
144287if [ ! -f ~ /.tmux.conf ]; then
145288 cat > ~ /.tmux.conf << 'EOF '
0 commit comments