aidevops 3.13.95 → 3.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/VERSION +1 -1
- package/aidevops.sh +44 -26
- package/package.json +1 -1
- package/setup.sh +25 -21
- package/aidevops-init-lib.sh +0 -1411
- package/aidevops-repos-lib.sh +0 -700
- package/aidevops-skills-plugin-lib.sh +0 -697
- package/aidevops-status-lib.sh +0 -141
- package/aidevops-update-lib.sh +0 -512
- package/aidevops-upgrade-planning-lib.sh +0 -370
- package/setup-modules/agent-deploy.sh +0 -1035
- package/setup-modules/agent-runtime.sh +0 -287
- package/setup-modules/config.sh +0 -478
- package/setup-modules/core.sh +0 -736
- package/setup-modules/mcp-setup.sh +0 -947
- package/setup-modules/migrations.sh +0 -1688
- package/setup-modules/plugins.sh +0 -728
- package/setup-modules/post-setup.sh +0 -301
- package/setup-modules/schedulers-linux.sh +0 -386
- package/setup-modules/schedulers-platform.sh +0 -1072
- package/setup-modules/schedulers-pulse.sh +0 -978
- package/setup-modules/schedulers.sh +0 -565
- package/setup-modules/shell-env.sh +0 -1240
- package/setup-modules/tool-beads.sh +0 -324
- package/setup-modules/tool-install.sh +0 -2134
|
@@ -1,1240 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# SPDX-FileCopyrightText: 2025-2026 Marcus Quinn
|
|
4
|
-
# Shell environment setup functions: oh-my-zsh, shell-compat, aliases, terminal-title
|
|
5
|
-
# Part of aidevops setup.sh modularization (t316.3)
|
|
6
|
-
|
|
7
|
-
# Shell safety baseline
|
|
8
|
-
set -Eeuo pipefail
|
|
9
|
-
IFS=$'\n\t'
|
|
10
|
-
# shellcheck disable=SC2154 # rc is assigned by $? in the trap string
|
|
11
|
-
trap 'rc=$?; echo "[ERROR] ${BASH_SOURCE[0]}:${LINENO} exit $rc" >&2' ERR
|
|
12
|
-
shopt -s inherit_errexit 2>/dev/null || true
|
|
13
|
-
|
|
14
|
-
# Detect the shell currently executing this script (zsh, bash, or fallback)
|
|
15
|
-
detect_running_shell() {
|
|
16
|
-
if [[ -n "${ZSH_VERSION:-}" ]]; then
|
|
17
|
-
echo "zsh"
|
|
18
|
-
elif [[ -n "${BASH_VERSION:-}" ]]; then
|
|
19
|
-
echo "bash"
|
|
20
|
-
else
|
|
21
|
-
basename "${SHELL:-/bin/bash}"
|
|
22
|
-
fi
|
|
23
|
-
return 0
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
# Detect the user's default login shell from the system (not $SHELL env var,
|
|
27
|
-
# which reflects the current shell, not the system default).
|
|
28
|
-
detect_default_shell() {
|
|
29
|
-
local user_name shell_path
|
|
30
|
-
user_name="$(id -un 2>/dev/null || whoami)"
|
|
31
|
-
shell_path=""
|
|
32
|
-
|
|
33
|
-
if [[ "$(uname)" == "Darwin" ]]; then
|
|
34
|
-
shell_path="$(dscl . -read "/Users/$user_name" UserShell 2>/dev/null | awk 'NR==1 {print $2}' || true)"
|
|
35
|
-
else
|
|
36
|
-
if command -v getent >/dev/null 2>&1; then
|
|
37
|
-
shell_path="$(getent passwd "$user_name" 2>/dev/null | cut -d: -f7 || true)"
|
|
38
|
-
fi
|
|
39
|
-
fi
|
|
40
|
-
|
|
41
|
-
# Fallback to $SHELL if system query returned empty
|
|
42
|
-
[[ -z "$shell_path" ]] && shell_path="${SHELL:-/bin/bash}"
|
|
43
|
-
basename "$shell_path"
|
|
44
|
-
return 0
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
# Usage: get_shell_rc "zsh" or get_shell_rc "bash"
|
|
48
|
-
get_shell_rc() {
|
|
49
|
-
local shell_name
|
|
50
|
-
shell_name="$1"
|
|
51
|
-
case "$shell_name" in
|
|
52
|
-
zsh)
|
|
53
|
-
echo "$HOME/.zshrc"
|
|
54
|
-
;;
|
|
55
|
-
bash)
|
|
56
|
-
if [[ "$(uname)" == "Darwin" ]]; then
|
|
57
|
-
echo "$HOME/.bash_profile"
|
|
58
|
-
else
|
|
59
|
-
echo "$HOME/.bashrc"
|
|
60
|
-
fi
|
|
61
|
-
;;
|
|
62
|
-
fish)
|
|
63
|
-
echo "$HOME/.config/fish/config.fish"
|
|
64
|
-
;;
|
|
65
|
-
ksh)
|
|
66
|
-
echo "$HOME/.kshrc"
|
|
67
|
-
;;
|
|
68
|
-
*)
|
|
69
|
-
# Fallback: check common rc files
|
|
70
|
-
if [[ -f "$HOME/.zshrc" ]]; then
|
|
71
|
-
echo "$HOME/.zshrc"
|
|
72
|
-
elif [[ -f "$HOME/.bashrc" ]]; then
|
|
73
|
-
echo "$HOME/.bashrc"
|
|
74
|
-
elif [[ -f "$HOME/.bash_profile" ]]; then
|
|
75
|
-
echo "$HOME/.bash_profile"
|
|
76
|
-
else
|
|
77
|
-
echo ""
|
|
78
|
-
fi
|
|
79
|
-
;;
|
|
80
|
-
esac
|
|
81
|
-
return 0
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
# Return all relevant shell rc file paths for the current platform
|
|
85
|
-
get_all_shell_rcs() {
|
|
86
|
-
local rcs=()
|
|
87
|
-
|
|
88
|
-
if [[ "$(uname)" == "Darwin" ]]; then
|
|
89
|
-
# macOS: always include zsh (default since Catalina) and bash_profile
|
|
90
|
-
[[ -f "$HOME/.zshrc" ]] && rcs+=("$HOME/.zshrc")
|
|
91
|
-
[[ -f "$HOME/.bash_profile" ]] && rcs+=("$HOME/.bash_profile")
|
|
92
|
-
# If neither exists, create .zshrc (macOS default)
|
|
93
|
-
if [[ ${#rcs[@]} -eq 0 ]]; then
|
|
94
|
-
touch "$HOME/.zshrc"
|
|
95
|
-
rcs+=("$HOME/.zshrc")
|
|
96
|
-
fi
|
|
97
|
-
else
|
|
98
|
-
# Linux: use the default shell's rc file
|
|
99
|
-
local default_shell
|
|
100
|
-
default_shell=$(detect_default_shell)
|
|
101
|
-
local rc
|
|
102
|
-
rc=$(get_shell_rc "$default_shell")
|
|
103
|
-
if [[ -n "$rc" ]]; then
|
|
104
|
-
rcs+=("$rc")
|
|
105
|
-
fi
|
|
106
|
-
fi
|
|
107
|
-
|
|
108
|
-
printf '%s\n' "${rcs[@]}"
|
|
109
|
-
return 0
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
# Offer to change the default shell to zsh after Oh My Zsh is installed.
|
|
113
|
-
_omz_offer_shell_change() {
|
|
114
|
-
local default_shell="$1"
|
|
115
|
-
|
|
116
|
-
if [[ "$default_shell" == "zsh" ]]; then
|
|
117
|
-
return 0
|
|
118
|
-
fi
|
|
119
|
-
|
|
120
|
-
echo ""
|
|
121
|
-
setup_prompt change_shell "Change default shell to zsh? [y/N]: " "n"
|
|
122
|
-
if [[ "$change_shell" =~ ^[Yy]$ ]]; then
|
|
123
|
-
if chsh -s "$(command -v zsh)"; then
|
|
124
|
-
print_success "Default shell changed to zsh"
|
|
125
|
-
print_info "Restart your terminal for the change to take effect"
|
|
126
|
-
else
|
|
127
|
-
print_warning "Failed to change shell - run manually: chsh -s $(command -v zsh)"
|
|
128
|
-
fi
|
|
129
|
-
fi
|
|
130
|
-
|
|
131
|
-
return 0
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
# Run the Oh My Zsh installer and handle post-install steps.
|
|
135
|
-
_omz_run_install() {
|
|
136
|
-
local default_shell="$1"
|
|
137
|
-
|
|
138
|
-
print_info "Installing Oh My Zsh..."
|
|
139
|
-
# Use verified download + --unattended to avoid changing the shell or starting zsh
|
|
140
|
-
# shellcheck disable=SC2034 # Read by verified_install() in setup.sh
|
|
141
|
-
VERIFIED_INSTALL_SHELL="sh"
|
|
142
|
-
if verified_install "Oh My Zsh" "https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh" --unattended; then
|
|
143
|
-
print_success "Oh My Zsh installed"
|
|
144
|
-
if [[ ! -f "$HOME/.zshrc" ]]; then
|
|
145
|
-
print_warning ".zshrc not created - Oh My Zsh may not have installed correctly"
|
|
146
|
-
fi
|
|
147
|
-
_omz_offer_shell_change "$default_shell"
|
|
148
|
-
else
|
|
149
|
-
print_warning "Oh My Zsh installation failed"
|
|
150
|
-
print_info "Install manually: curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh -o /tmp/omz-install.sh && sh /tmp/omz-install.sh"
|
|
151
|
-
fi
|
|
152
|
-
|
|
153
|
-
return 0
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
# Offer to install Oh My Zsh if zsh is the default shell and OMZ is not present
|
|
157
|
-
setup_oh_my_zsh() {
|
|
158
|
-
# Check prerequisites before announcing setup (GH#5240)
|
|
159
|
-
if ! command -v zsh >/dev/null 2>&1; then
|
|
160
|
-
print_skip "Oh My Zsh" "zsh not installed" "Install zsh first, then re-run setup"
|
|
161
|
-
setup_track_skipped "Oh My Zsh" "zsh not installed"
|
|
162
|
-
return 0
|
|
163
|
-
fi
|
|
164
|
-
|
|
165
|
-
if [[ -d "$HOME/.oh-my-zsh" ]]; then
|
|
166
|
-
print_success "Oh My Zsh already installed"
|
|
167
|
-
setup_track_configured "Oh My Zsh"
|
|
168
|
-
return 0
|
|
169
|
-
fi
|
|
170
|
-
|
|
171
|
-
local default_shell
|
|
172
|
-
default_shell=$(detect_default_shell)
|
|
173
|
-
|
|
174
|
-
if [[ "$default_shell" != "zsh" && "$(uname)" != "Darwin" ]]; then
|
|
175
|
-
print_skip "Oh My Zsh" "default shell is $default_shell (not zsh)" "Change default shell to zsh: chsh -s \$(which zsh)"
|
|
176
|
-
setup_track_skipped "Oh My Zsh" "default shell is $default_shell"
|
|
177
|
-
return 0
|
|
178
|
-
fi
|
|
179
|
-
|
|
180
|
-
print_info "Oh My Zsh enhances zsh with themes, plugins, and completions"
|
|
181
|
-
echo " Many tools installed later (git, fd, brew) benefit from Oh My Zsh plugins."
|
|
182
|
-
echo " This is optional - plain zsh works fine without it."
|
|
183
|
-
echo ""
|
|
184
|
-
|
|
185
|
-
setup_prompt install_omz "Install Oh My Zsh? [y/N]: " "n"
|
|
186
|
-
|
|
187
|
-
if [[ "$install_omz" =~ ^[Yy]$ ]]; then
|
|
188
|
-
_omz_run_install "$default_shell"
|
|
189
|
-
else
|
|
190
|
-
print_info "Skipped Oh My Zsh installation"
|
|
191
|
-
print_info "Install later: curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh -o /tmp/omz-install.sh && sh /tmp/omz-install.sh"
|
|
192
|
-
fi
|
|
193
|
-
|
|
194
|
-
return 0
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
# Check that both zsh and bash are installed and collect existing bash config files.
|
|
198
|
-
# Prints the bash config file paths (one per line) on success.
|
|
199
|
-
# Returns 1 if prerequisites are not met (caller should return 0 early).
|
|
200
|
-
_shell_compat_check_prereqs() {
|
|
201
|
-
local shared_profile="$1"
|
|
202
|
-
local zsh_rc="$2"
|
|
203
|
-
|
|
204
|
-
if [[ -f "$shared_profile" ]]; then
|
|
205
|
-
print_success "Cross-shell compatibility already configured ($shared_profile)"
|
|
206
|
-
return 1
|
|
207
|
-
fi
|
|
208
|
-
|
|
209
|
-
if ! command -v zsh >/dev/null 2>&1; then
|
|
210
|
-
print_info "zsh not installed - cross-shell setup not needed"
|
|
211
|
-
return 1
|
|
212
|
-
fi
|
|
213
|
-
if ! command -v bash >/dev/null 2>&1; then
|
|
214
|
-
print_info "bash not installed - cross-shell setup not needed"
|
|
215
|
-
return 1
|
|
216
|
-
fi
|
|
217
|
-
|
|
218
|
-
# Collect all bash config files that exist
|
|
219
|
-
# macOS: .bash_profile (login) + .bashrc (interactive, often sourced by .bash_profile)
|
|
220
|
-
# Linux: .bashrc (primary) + .bash_profile (login, often sources .bashrc)
|
|
221
|
-
# We check all of them on both platforms since tools write to either
|
|
222
|
-
local -a bash_files=()
|
|
223
|
-
[[ -f "$HOME/.bash_profile" ]] && bash_files+=("$HOME/.bash_profile")
|
|
224
|
-
[[ -f "$HOME/.bashrc" ]] && bash_files+=("$HOME/.bashrc")
|
|
225
|
-
[[ -f "$HOME/.profile" ]] && bash_files+=("$HOME/.profile")
|
|
226
|
-
|
|
227
|
-
if [[ ${#bash_files[@]} -eq 0 ]]; then
|
|
228
|
-
print_info "No bash config files found - skipping cross-shell setup"
|
|
229
|
-
return 1
|
|
230
|
-
fi
|
|
231
|
-
|
|
232
|
-
if [[ ! -f "$zsh_rc" ]]; then
|
|
233
|
-
print_info "No .zshrc found - skipping cross-shell setup"
|
|
234
|
-
return 1
|
|
235
|
-
fi
|
|
236
|
-
|
|
237
|
-
printf '%s\n' "${bash_files[@]}"
|
|
238
|
-
return 0
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
# Count portable customizations (exports, aliases, PATH entries) across bash config files.
|
|
242
|
-
# Prints "exports aliases paths" space-separated.
|
|
243
|
-
_shell_compat_count_customizations() {
|
|
244
|
-
local total_exports=0
|
|
245
|
-
local total_aliases=0
|
|
246
|
-
local total_paths=0
|
|
247
|
-
|
|
248
|
-
local src_file
|
|
249
|
-
for src_file in "$@"; do
|
|
250
|
-
local n
|
|
251
|
-
# grep -c exits 1 on no match; || : prevents ERR trap noise
|
|
252
|
-
# File existence already verified when building bash_files array
|
|
253
|
-
n=$(grep -cE '^\s*export\s+[A-Z]' "$src_file" || :)
|
|
254
|
-
total_exports=$((total_exports + ${n:-0}))
|
|
255
|
-
n=$(grep -cE '^\s*alias\s+' "$src_file" || :)
|
|
256
|
-
total_aliases=$((total_aliases + ${n:-0}))
|
|
257
|
-
n=$(grep -cE 'PATH.*=' "$src_file" || :)
|
|
258
|
-
total_paths=$((total_paths + ${n:-0}))
|
|
259
|
-
done
|
|
260
|
-
|
|
261
|
-
echo "$total_exports $total_aliases $total_paths"
|
|
262
|
-
return 0
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
# Return 0 if the line is bash-specific and should NOT be extracted to shared profile.
|
|
266
|
-
_shell_compat_is_bash_specific() {
|
|
267
|
-
local line="$1"
|
|
268
|
-
case "$line" in
|
|
269
|
-
*shopt*) return 0 ;;
|
|
270
|
-
*PROMPT_COMMAND*) return 0 ;;
|
|
271
|
-
*PS1=*) return 0 ;;
|
|
272
|
-
*PS2=*) return 0 ;;
|
|
273
|
-
*bash_completion*) return 0 ;;
|
|
274
|
-
*"complete "*) return 0 ;;
|
|
275
|
-
*"bind "*) return 0 ;;
|
|
276
|
-
*HISTCONTROL*) return 0 ;;
|
|
277
|
-
*HISTFILESIZE*) return 0 ;;
|
|
278
|
-
*HISTSIZE*) return 0 ;;
|
|
279
|
-
*"source /etc/bash"*) return 0 ;;
|
|
280
|
-
*". /etc/bash"*) return 0 ;;
|
|
281
|
-
*"source /etc/profile"*) return 0 ;;
|
|
282
|
-
*". /etc/profile"*) return 0 ;;
|
|
283
|
-
# Skip lines that source .bashrc from .bash_profile (circular)
|
|
284
|
-
*".bashrc"*) return 0 ;;
|
|
285
|
-
# Skip lines that source .shell_common (we'll add this ourselves)
|
|
286
|
-
*"shell_common"*) return 0 ;;
|
|
287
|
-
esac
|
|
288
|
-
return 1
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
# Return 0 if the line is a portable shell customization (exports, aliases, PATH, etc.).
|
|
292
|
-
_shell_compat_is_portable() {
|
|
293
|
-
local line="$1"
|
|
294
|
-
case "$line" in
|
|
295
|
-
export\ [A-Z]* | export\ PATH*) return 0 ;;
|
|
296
|
-
alias\ *) return 0 ;;
|
|
297
|
-
eval\ *) return 0 ;;
|
|
298
|
-
*PATH=*) return 0 ;;
|
|
299
|
-
# Also match 'source' and '. ' commands (tool integrations like nvm, rvm, pyenv)
|
|
300
|
-
source\ * | .\ /* | .\ \$* | .\ \~*) return 0 ;;
|
|
301
|
-
esac
|
|
302
|
-
return 1
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
# Write the header block for the shared profile file.
|
|
306
|
-
_shell_compat_write_profile_header() {
|
|
307
|
-
local shared_profile="$1"
|
|
308
|
-
|
|
309
|
-
{
|
|
310
|
-
echo "# Shared shell profile - sourced by both bash and zsh"
|
|
311
|
-
echo "# Created by aidevops setup to preserve customizations across shell switches"
|
|
312
|
-
echo "# Edit this file for settings you want in BOTH bash and zsh"
|
|
313
|
-
echo "# Shell-specific settings go in ~/.bashrc or ~/.zshrc"
|
|
314
|
-
echo ""
|
|
315
|
-
} >"$shared_profile"
|
|
316
|
-
|
|
317
|
-
return 0
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
# Extract portable lines from one source file into the shared profile.
|
|
321
|
-
# Skips duplicates (tracked via seen_lines nameref-style via global).
|
|
322
|
-
# Prints the number of lines extracted from this file.
|
|
323
|
-
# Args: shared_profile src_file [seen_line1 seen_line2 ...]
|
|
324
|
-
# Returns extracted count via stdout; seen lines via stdout after count (newline-separated).
|
|
325
|
-
_shell_compat_extract_one_file() {
|
|
326
|
-
local shared_profile="$1"
|
|
327
|
-
local src_file="$2"
|
|
328
|
-
shift 2
|
|
329
|
-
# remaining args are already-seen lines
|
|
330
|
-
|
|
331
|
-
local src_basename
|
|
332
|
-
src_basename=$(basename "$src_file")
|
|
333
|
-
local added_header=false
|
|
334
|
-
local extracted=0
|
|
335
|
-
|
|
336
|
-
# Build a local seen set from passed args
|
|
337
|
-
local -a seen_lines=("$@")
|
|
338
|
-
|
|
339
|
-
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
340
|
-
[[ -z "$line" ]] && continue
|
|
341
|
-
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
|
342
|
-
_shell_compat_is_bash_specific "$line" && continue
|
|
343
|
-
_shell_compat_is_portable "$line" || continue
|
|
344
|
-
|
|
345
|
-
# Deduplicate
|
|
346
|
-
local is_dup=false
|
|
347
|
-
local seen
|
|
348
|
-
for seen in "${seen_lines[@]+"${seen_lines[@]}"}"; do
|
|
349
|
-
if [[ "$seen" == "$line" ]]; then
|
|
350
|
-
is_dup=true
|
|
351
|
-
break
|
|
352
|
-
fi
|
|
353
|
-
done
|
|
354
|
-
[[ "$is_dup" == "true" ]] && continue
|
|
355
|
-
|
|
356
|
-
if [[ "$added_header" == "false" ]]; then
|
|
357
|
-
echo "" >>"$shared_profile"
|
|
358
|
-
echo "# From $src_basename" >>"$shared_profile"
|
|
359
|
-
added_header=true
|
|
360
|
-
fi
|
|
361
|
-
echo "$line" >>"$shared_profile"
|
|
362
|
-
seen_lines+=("$line")
|
|
363
|
-
((++extracted))
|
|
364
|
-
done <"$src_file"
|
|
365
|
-
|
|
366
|
-
# Output: count on first line, then new seen lines (for caller to accumulate)
|
|
367
|
-
echo "$extracted"
|
|
368
|
-
printf '%s\n' "${seen_lines[@]+"${seen_lines[@]}"}"
|
|
369
|
-
return 0
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
# Extract portable customizations from bash config files into the shared profile.
|
|
373
|
-
# Returns the count of extracted lines.
|
|
374
|
-
_shell_compat_extract_to_shared_profile() {
|
|
375
|
-
local shared_profile="$1"
|
|
376
|
-
shift
|
|
377
|
-
# remaining args are bash_files
|
|
378
|
-
|
|
379
|
-
_shell_compat_write_profile_header "$shared_profile"
|
|
380
|
-
|
|
381
|
-
local -a seen_lines=()
|
|
382
|
-
local extracted=0
|
|
383
|
-
|
|
384
|
-
local src_file
|
|
385
|
-
for src_file in "$@"; do
|
|
386
|
-
local file_out
|
|
387
|
-
file_out=$(_shell_compat_extract_one_file "$shared_profile" "$src_file" "${seen_lines[@]+"${seen_lines[@]}"}")
|
|
388
|
-
local file_count
|
|
389
|
-
file_count=$(printf '%s\n' "$file_out" | head -1)
|
|
390
|
-
extracted=$((extracted + file_count))
|
|
391
|
-
# Rebuild seen_lines from output (skip first line = count)
|
|
392
|
-
local -a new_seen=()
|
|
393
|
-
while IFS= read -r seen_line; do
|
|
394
|
-
[[ -n "$seen_line" ]] && new_seen+=("$seen_line")
|
|
395
|
-
done < <(printf '%s\n' "$file_out" | tail -n +2)
|
|
396
|
-
seen_lines=("${new_seen[@]+"${new_seen[@]}"}")
|
|
397
|
-
done
|
|
398
|
-
|
|
399
|
-
echo "$extracted"
|
|
400
|
-
return 0
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
# Add sourcing of the shared profile to .zshrc and all bash config files.
|
|
404
|
-
_shell_compat_add_sourcing() {
|
|
405
|
-
local zsh_rc="$1"
|
|
406
|
-
shift
|
|
407
|
-
# remaining args are bash_files
|
|
408
|
-
|
|
409
|
-
# Add sourcing to .zshrc if not already present (existence verified above)
|
|
410
|
-
if ! grep -q 'shell_common' "$zsh_rc"; then
|
|
411
|
-
{
|
|
412
|
-
echo ""
|
|
413
|
-
echo "# Cross-shell compatibility (added by aidevops setup)"
|
|
414
|
-
echo "# Sources shared profile so bash customizations work in zsh too"
|
|
415
|
-
# shellcheck disable=SC2016
|
|
416
|
-
echo '[ -f "$HOME/.shell_common" ] && . "$HOME/.shell_common"'
|
|
417
|
-
} >>"$zsh_rc"
|
|
418
|
-
print_success "Added shared profile sourcing to .zshrc"
|
|
419
|
-
fi
|
|
420
|
-
|
|
421
|
-
# Add sourcing to bash config files if not already present
|
|
422
|
-
# File existence already verified when building bash_files array
|
|
423
|
-
local src_file
|
|
424
|
-
for src_file in "$@"; do
|
|
425
|
-
if ! grep -q 'shell_common' "$src_file"; then
|
|
426
|
-
{
|
|
427
|
-
echo ""
|
|
428
|
-
echo "# Cross-shell compatibility (added by aidevops setup)"
|
|
429
|
-
echo "# Shared profile - edit ~/.shell_common for settings in both shells"
|
|
430
|
-
# shellcheck disable=SC2016
|
|
431
|
-
echo '[ -f "$HOME/.shell_common" ] && . "$HOME/.shell_common"'
|
|
432
|
-
} >>"$src_file"
|
|
433
|
-
print_success "Added shared profile sourcing to $(basename "$src_file")"
|
|
434
|
-
fi
|
|
435
|
-
done
|
|
436
|
-
|
|
437
|
-
return 0
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
# Print detected customization counts and prompt the user.
|
|
441
|
-
# Returns 1 if the user declines (caller should return 0).
|
|
442
|
-
_shell_compat_prompt_user() {
|
|
443
|
-
local file_count="$1"
|
|
444
|
-
local total_exports="$2"
|
|
445
|
-
local total_aliases="$3"
|
|
446
|
-
local total_paths="$4"
|
|
447
|
-
|
|
448
|
-
print_info "Detected bash customizations across ${file_count} file(s):"
|
|
449
|
-
echo " Exports: $total_exports, Aliases: $total_aliases, PATH entries: $total_paths"
|
|
450
|
-
echo ""
|
|
451
|
-
print_info "Best practice: create a shared profile (~/.shell_common) sourced by"
|
|
452
|
-
print_info "both bash and zsh, so your customizations work in either shell."
|
|
453
|
-
echo ""
|
|
454
|
-
|
|
455
|
-
local setup_compat
|
|
456
|
-
setup_prompt setup_compat "Create shared shell profile for cross-shell compatibility? [Y/n]: " "Y"
|
|
457
|
-
|
|
458
|
-
if [[ ! "$setup_compat" =~ ^[Yy]?$ ]]; then
|
|
459
|
-
print_info "Skipped cross-shell compatibility setup"
|
|
460
|
-
print_info "Set up later by creating ~/.shell_common and sourcing it from both shells"
|
|
461
|
-
return 1
|
|
462
|
-
fi
|
|
463
|
-
|
|
464
|
-
return 0
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
# Do the extraction and sourcing steps, then print the success summary.
|
|
468
|
-
_shell_compat_do_extract() {
|
|
469
|
-
local shared_profile="$1"
|
|
470
|
-
local zsh_rc="$2"
|
|
471
|
-
shift 2
|
|
472
|
-
# remaining args are bash_files
|
|
473
|
-
|
|
474
|
-
# We extract: exports, PATH modifications, aliases, eval statements, source commands
|
|
475
|
-
# We skip: bash-specific syntax (shopt, PROMPT_COMMAND, PS1, completion, bind, etc.)
|
|
476
|
-
# We deduplicate lines that appear in multiple files (e.g. .bash_profile sources .bashrc)
|
|
477
|
-
print_info "Creating shared profile: $shared_profile"
|
|
478
|
-
|
|
479
|
-
local extracted
|
|
480
|
-
extracted=$(_shell_compat_extract_to_shared_profile "$shared_profile" "$@")
|
|
481
|
-
|
|
482
|
-
if [[ $extracted -eq 0 ]]; then
|
|
483
|
-
rm -f "$shared_profile"
|
|
484
|
-
print_info "No portable customizations found to extract"
|
|
485
|
-
return 0
|
|
486
|
-
fi
|
|
487
|
-
|
|
488
|
-
chmod 644 "$shared_profile"
|
|
489
|
-
print_success "Extracted $extracted unique customization(s) to $shared_profile"
|
|
490
|
-
_shell_compat_add_sourcing "$zsh_rc" "$@"
|
|
491
|
-
|
|
492
|
-
echo ""
|
|
493
|
-
print_success "Cross-shell compatibility configured"
|
|
494
|
-
print_info "Your customizations are now in: $shared_profile"
|
|
495
|
-
print_info "Both bash and zsh will source this file automatically."
|
|
496
|
-
print_info "Edit ~/.shell_common for settings you want in both shells."
|
|
497
|
-
print_info "Use ~/.bashrc or ~/.zshrc for shell-specific settings only."
|
|
498
|
-
|
|
499
|
-
return 0
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
# Extract portable customizations from bash configs into a shared profile for cross-shell use
|
|
503
|
-
setup_shell_compatibility() {
|
|
504
|
-
print_info "Setting up cross-shell compatibility..."
|
|
505
|
-
|
|
506
|
-
local shared_profile="$HOME/.shell_common"
|
|
507
|
-
local zsh_rc="$HOME/.zshrc"
|
|
508
|
-
|
|
509
|
-
# Check prerequisites; collect bash config files
|
|
510
|
-
local -a bash_files=()
|
|
511
|
-
local prereq_out
|
|
512
|
-
prereq_out=$(_shell_compat_check_prereqs "$shared_profile" "$zsh_rc") || return 0
|
|
513
|
-
while IFS= read -r line; do
|
|
514
|
-
[[ -n "$line" ]] && bash_files+=("$line")
|
|
515
|
-
done <<<"$prereq_out"
|
|
516
|
-
|
|
517
|
-
# Count customizations across all bash config files
|
|
518
|
-
local counts
|
|
519
|
-
counts=$(_shell_compat_count_customizations "${bash_files[@]}")
|
|
520
|
-
local total_exports total_aliases total_paths
|
|
521
|
-
read -r total_exports total_aliases total_paths <<<"$counts"
|
|
522
|
-
|
|
523
|
-
if [[ $total_exports -eq 0 && $total_aliases -eq 0 && $total_paths -eq 0 ]]; then
|
|
524
|
-
print_info "No bash customizations detected - skipping cross-shell setup"
|
|
525
|
-
return 0
|
|
526
|
-
fi
|
|
527
|
-
|
|
528
|
-
_shell_compat_prompt_user "${#bash_files[@]}" "$total_exports" "$total_aliases" "$total_paths" || return 0
|
|
529
|
-
_shell_compat_do_extract "$shared_profile" "$zsh_rc" "${bash_files[@]}"
|
|
530
|
-
|
|
531
|
-
return 0
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
# Check for optional dependencies (sshpass) and offer to install them
|
|
535
|
-
check_optional_deps() {
|
|
536
|
-
print_info "Checking optional dependencies..."
|
|
537
|
-
|
|
538
|
-
local missing_optional=()
|
|
539
|
-
|
|
540
|
-
if ! command -v sshpass >/dev/null 2>&1; then
|
|
541
|
-
missing_optional+=("sshpass")
|
|
542
|
-
else
|
|
543
|
-
print_success "sshpass found"
|
|
544
|
-
fi
|
|
545
|
-
|
|
546
|
-
check_python_version "" "skills/tools" >/dev/null || true
|
|
547
|
-
|
|
548
|
-
if [[ ${#missing_optional[@]} -gt 0 ]]; then
|
|
549
|
-
print_warning "Missing optional dependencies: ${missing_optional[*]}"
|
|
550
|
-
echo " sshpass - needed for password-based SSH (like Hostinger)"
|
|
551
|
-
|
|
552
|
-
local pkg_manager
|
|
553
|
-
pkg_manager=$(detect_package_manager)
|
|
554
|
-
|
|
555
|
-
if [[ "$pkg_manager" != "unknown" ]]; then
|
|
556
|
-
setup_prompt install_optional "Install optional dependencies using $pkg_manager? [Y/n]: " "Y"
|
|
557
|
-
|
|
558
|
-
if [[ "$install_optional" =~ ^[Yy]?$ ]]; then
|
|
559
|
-
print_info "Installing ${missing_optional[*]}..."
|
|
560
|
-
if install_packages "$pkg_manager" "${missing_optional[@]}"; then
|
|
561
|
-
print_success "Optional dependencies installed"
|
|
562
|
-
else
|
|
563
|
-
print_warning "Failed to install optional dependencies (non-critical)"
|
|
564
|
-
fi
|
|
565
|
-
else
|
|
566
|
-
print_info "Skipped optional dependencies"
|
|
567
|
-
fi
|
|
568
|
-
fi
|
|
569
|
-
fi
|
|
570
|
-
return 0
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
# Update a single rc file to include ~/.local/bin on PATH.
|
|
574
|
-
# Prints "added:<file>" or "already:<file>" to stdout.
|
|
575
|
-
_local_bin_update_rc_file() {
|
|
576
|
-
local rc_file="$1"
|
|
577
|
-
local path_line="$2"
|
|
578
|
-
|
|
579
|
-
# Create the rc file if it doesn't exist (ensure parent dir exists for fish etc.)
|
|
580
|
-
if [[ ! -f "$rc_file" ]]; then
|
|
581
|
-
mkdir -p "$(dirname "$rc_file")"
|
|
582
|
-
touch "$rc_file"
|
|
583
|
-
fi
|
|
584
|
-
|
|
585
|
-
# Check if already added (file created above if it didn't exist)
|
|
586
|
-
if grep -q '\.local/bin' "$rc_file"; then
|
|
587
|
-
echo "already:$rc_file"
|
|
588
|
-
return 0
|
|
589
|
-
fi
|
|
590
|
-
|
|
591
|
-
# Add to shell config
|
|
592
|
-
{
|
|
593
|
-
echo ""
|
|
594
|
-
echo "# Added by aidevops setup"
|
|
595
|
-
echo "$path_line"
|
|
596
|
-
} >>"$rc_file"
|
|
597
|
-
echo "added:$rc_file"
|
|
598
|
-
return 0
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
# Print result messages for add_local_bin_to_path.
|
|
602
|
-
_local_bin_report_results() {
|
|
603
|
-
local added_to="$1"
|
|
604
|
-
local already_in="$2"
|
|
605
|
-
local path_line="$3"
|
|
606
|
-
|
|
607
|
-
if [[ -n "$added_to" ]]; then
|
|
608
|
-
print_success "Added $HOME/.local/bin to PATH in: $added_to"
|
|
609
|
-
print_info "Restart your terminal to use 'aidevops' command"
|
|
610
|
-
fi
|
|
611
|
-
|
|
612
|
-
if [[ -n "$already_in" ]]; then
|
|
613
|
-
print_info "$HOME/.local/bin already in PATH in: $already_in"
|
|
614
|
-
fi
|
|
615
|
-
|
|
616
|
-
if [[ -z "$added_to" && -z "$already_in" ]]; then
|
|
617
|
-
print_warning "Could not detect shell config file"
|
|
618
|
-
print_info "Add this to your shell config: $path_line"
|
|
619
|
-
fi
|
|
620
|
-
|
|
621
|
-
return 0
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
# Add ~/.local/bin to PATH in all shell rc files for the aidevops CLI
|
|
625
|
-
add_local_bin_to_path() {
|
|
626
|
-
# shellcheck disable=SC2016 # path_line is written to rc files; must expand at shell startup, not now
|
|
627
|
-
local path_line='export PATH="$HOME/.local/bin:$PATH"'
|
|
628
|
-
local added_to=""
|
|
629
|
-
local already_in=""
|
|
630
|
-
|
|
631
|
-
local rc_file
|
|
632
|
-
while IFS= read -r rc_file; do
|
|
633
|
-
[[ -z "$rc_file" ]] && continue
|
|
634
|
-
local result
|
|
635
|
-
result=$(_local_bin_update_rc_file "$rc_file" "$path_line")
|
|
636
|
-
case "$result" in
|
|
637
|
-
added:*) added_to="${added_to:+$added_to, }${result#added:}" ;;
|
|
638
|
-
already:*) already_in="${already_in:+$already_in, }${result#already:}" ;;
|
|
639
|
-
esac
|
|
640
|
-
done < <(get_all_shell_rcs)
|
|
641
|
-
|
|
642
|
-
_local_bin_report_results "$added_to" "$already_in" "$path_line"
|
|
643
|
-
|
|
644
|
-
# Also export for current session
|
|
645
|
-
export PATH="$HOME/.local/bin:$PATH"
|
|
646
|
-
|
|
647
|
-
return 0
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
# GH#2915, GH#2993: Ensure all processes use the safe ShellCheck wrapper.
|
|
651
|
-
#
|
|
652
|
-
# The bash language server hardcodes --external-sources in every ShellCheck
|
|
653
|
-
# invocation, causing exponential memory growth (9+ GB) when source chains
|
|
654
|
-
# span 463+ scripts. The wrapper strips --external-sources and enforces a
|
|
655
|
-
# background RSS watchdog (ulimit -v is broken on macOS ARM — EINVAL).
|
|
656
|
-
#
|
|
657
|
-
# GH#2915 set SHELLCHECK_PATH env var, but bash-language-server ignores it —
|
|
658
|
-
# it resolves `shellcheck` via PATH lookup, finding /opt/homebrew/bin/shellcheck
|
|
659
|
-
# directly. GH#2993 fixes this by placing a shim on PATH ahead of the real binary.
|
|
660
|
-
#
|
|
661
|
-
# Four layers ensure all processes use the wrapper:
|
|
662
|
-
# 0. PATH shim — ~/.aidevops/bin/shellcheck symlink + PATH prepend (GH#2993)
|
|
663
|
-
# 1. launchctl setenv (macOS) — GUI-launched apps (current boot only)
|
|
664
|
-
# 2. .zshenv — ALL zsh processes including non-interactive (persists)
|
|
665
|
-
# 3. Shell rc files (.zshrc, .bash_profile) — interactive terminals
|
|
666
|
-
#
|
|
667
|
-
# Layer 0 is the primary fix: bash-language-server does a PATH lookup for
|
|
668
|
-
# "shellcheck". By placing ~/.aidevops/bin first on PATH with a symlink to
|
|
669
|
-
# the wrapper, the language server finds the wrapper instead of the real binary.
|
|
670
|
-
# Layers 1-3 are retained for tools that honour SHELLCHECK_PATH.
|
|
671
|
-
#
|
|
672
|
-
# CRITICAL: ~/.aidevops/bin MUST be at the START of PATH, not the end.
|
|
673
|
-
# If it appears after /opt/homebrew/bin, the real shellcheck is found first
|
|
674
|
-
# and the wrapper is bypassed entirely. The launchctl setenv always prepends,
|
|
675
|
-
# and the case-guard in shell rc files ensures it stays first.
|
|
676
|
-
|
|
677
|
-
# Verify the shellcheck wrapper exists and is executable.
|
|
678
|
-
# Returns 1 if setup should be aborted (caller returns 0).
|
|
679
|
-
_shellcheck_wrapper_verify() {
|
|
680
|
-
local wrapper_path="$1"
|
|
681
|
-
|
|
682
|
-
if [[ ! -x "$wrapper_path" ]]; then
|
|
683
|
-
if [[ -f "$wrapper_path" ]]; then
|
|
684
|
-
chmod +x "$wrapper_path"
|
|
685
|
-
else
|
|
686
|
-
print_warning "ShellCheck wrapper not found at $wrapper_path (will be available after deploy)"
|
|
687
|
-
return 1
|
|
688
|
-
fi
|
|
689
|
-
fi
|
|
690
|
-
|
|
691
|
-
if ! "$wrapper_path" --version >/dev/null 2>&1; then
|
|
692
|
-
print_warning "ShellCheck wrapper cannot find real shellcheck binary — skipping"
|
|
693
|
-
return 1
|
|
694
|
-
fi
|
|
695
|
-
|
|
696
|
-
return 0
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
# Layer 0: Create the PATH shim (GH#2993).
|
|
700
|
-
# Places a symlink to the wrapper in ~/.aidevops/bin so bash-language-server
|
|
701
|
-
# finds the wrapper via PATH lookup before the real shellcheck binary.
|
|
702
|
-
_shellcheck_wrapper_setup_shim() {
|
|
703
|
-
local wrapper_path="$1"
|
|
704
|
-
local shim_dir="$HOME/.aidevops/bin"
|
|
705
|
-
local shim_path="$shim_dir/shellcheck"
|
|
706
|
-
|
|
707
|
-
mkdir -p "$shim_dir"
|
|
708
|
-
|
|
709
|
-
local wrapper_realpath
|
|
710
|
-
wrapper_realpath="$(realpath "$wrapper_path" 2>/dev/null || readlink -f "$wrapper_path" 2>/dev/null || echo "$wrapper_path")"
|
|
711
|
-
|
|
712
|
-
if [[ -L "$shim_path" ]]; then
|
|
713
|
-
local current_target
|
|
714
|
-
current_target="$(realpath "$shim_path" 2>/dev/null || readlink -f "$shim_path" 2>/dev/null || echo "")"
|
|
715
|
-
if [[ "$current_target" != "$wrapper_realpath" ]]; then
|
|
716
|
-
ln -sf "$wrapper_path" "$shim_path"
|
|
717
|
-
print_info "Updated shellcheck shim symlink: $shim_path → $wrapper_path"
|
|
718
|
-
fi
|
|
719
|
-
elif [[ -e "$shim_path" ]]; then
|
|
720
|
-
# Regular file exists — back up and replace with symlink
|
|
721
|
-
mv "$shim_path" "${shim_path}.bak.$(date +%Y%m%d_%H%M%S)"
|
|
722
|
-
ln -sf "$wrapper_path" "$shim_path"
|
|
723
|
-
print_info "Replaced shellcheck shim with symlink: $shim_path → $wrapper_path"
|
|
724
|
-
else
|
|
725
|
-
ln -sf "$wrapper_path" "$shim_path"
|
|
726
|
-
print_success "Created shellcheck shim: $shim_path → $wrapper_path"
|
|
727
|
-
fi
|
|
728
|
-
|
|
729
|
-
return 0
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
# Layer 1: Set SHELLCHECK_PATH and prepend shim dir via launchctl (macOS only).
|
|
733
|
-
# Affects all GUI-launched processes for the current boot session.
|
|
734
|
-
_shellcheck_wrapper_setup_launchctl() {
|
|
735
|
-
local wrapper_path="$1"
|
|
736
|
-
local shim_dir="$2"
|
|
737
|
-
|
|
738
|
-
# Note: 2>/dev/null on launchctl is intentional — launchctl may not be
|
|
739
|
-
# available in non-GUI contexts (SSH, containers). Unlike grep where we
|
|
740
|
-
# want errors visible, launchctl failure is a non-fatal fallback.
|
|
741
|
-
if launchctl setenv SHELLCHECK_PATH "$wrapper_path" 2>/dev/null; then
|
|
742
|
-
print_info "Set SHELLCHECK_PATH via launchctl (GUI processes)"
|
|
743
|
-
fi
|
|
744
|
-
|
|
745
|
-
# Build a clean PATH with shim_dir at the front, removing any existing
|
|
746
|
-
# occurrence to prevent duplicates while ensuring first position.
|
|
747
|
-
# Handle the empty-PATH edge case to avoid a trailing colon (which
|
|
748
|
-
# resolves to "." and is a PATH injection vector).
|
|
749
|
-
local clean_path
|
|
750
|
-
clean_path=$(printf '%s' "$PATH" | tr ':' '\n' | grep -Fxv "$shim_dir" | tr '\n' ':' | sed 's/:$//')
|
|
751
|
-
local new_path
|
|
752
|
-
if [[ -n "$clean_path" ]]; then
|
|
753
|
-
new_path="${shim_dir}:${clean_path}"
|
|
754
|
-
else
|
|
755
|
-
new_path="${shim_dir}"
|
|
756
|
-
fi
|
|
757
|
-
if launchctl setenv PATH "$new_path" 2>/dev/null; then
|
|
758
|
-
print_info "Prepended $shim_dir to PATH via launchctl (GUI processes)"
|
|
759
|
-
fi
|
|
760
|
-
|
|
761
|
-
return 0
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
# Layer 2: Configure SHELLCHECK_PATH and PATH shim in .zshenv.
|
|
765
|
-
# Affects ALL zsh processes including non-interactive (e.g. bash-language-server).
|
|
766
|
-
_shellcheck_wrapper_setup_zshenv() {
|
|
767
|
-
local env_line="$1"
|
|
768
|
-
local path_line="$2"
|
|
769
|
-
local shim_dir="$3"
|
|
770
|
-
local zshenv="$HOME/.zshenv"
|
|
771
|
-
local added_to_out=""
|
|
772
|
-
local already_in_out=""
|
|
773
|
-
|
|
774
|
-
if [[ -f "$zshenv" ]] || command -v zsh >/dev/null 2>&1; then
|
|
775
|
-
touch "$zshenv"
|
|
776
|
-
|
|
777
|
-
# SHELLCHECK_PATH env var (for tools that honour it)
|
|
778
|
-
if grep -q 'SHELLCHECK_PATH' "$zshenv"; then
|
|
779
|
-
already_in_out="$zshenv"
|
|
780
|
-
else
|
|
781
|
-
{
|
|
782
|
-
echo ""
|
|
783
|
-
echo "# Added by aidevops setup (GH#2915: prevent ShellCheck memory explosion)"
|
|
784
|
-
echo "$env_line"
|
|
785
|
-
} >>"$zshenv"
|
|
786
|
-
added_to_out="$zshenv"
|
|
787
|
-
fi
|
|
788
|
-
|
|
789
|
-
# PATH prepend for ~/.aidevops/bin (GH#2993: shim must be on PATH)
|
|
790
|
-
# Remove stale old-form entries (case guard that only checked presence,
|
|
791
|
-
# not position — left the shim at the end of PATH on upgrades)
|
|
792
|
-
# shellcheck disable=SC2016 # Matching literal $PATH text in rc files, not expanding
|
|
793
|
-
if grep -q 'case ":$PATH:" in.*\.aidevops/bin' "$zshenv"; then
|
|
794
|
-
# Remove the old case-guard line (sed is appropriate here — targeted single-line removal)
|
|
795
|
-
# shellcheck disable=SC2016
|
|
796
|
-
sed -i.bak '/case ":$PATH:" in.*\.aidevops\/bin/d' "$zshenv"
|
|
797
|
-
rm -f "${zshenv}.bak"
|
|
798
|
-
fi
|
|
799
|
-
# Use exact-line match for the new sanitize-and-prepend form
|
|
800
|
-
if ! grep -Fq '_aidevops_shim' "$zshenv"; then
|
|
801
|
-
{
|
|
802
|
-
echo ""
|
|
803
|
-
echo "# Added by aidevops setup (GH#2993: shellcheck shim on PATH)"
|
|
804
|
-
echo "$path_line"
|
|
805
|
-
} >>"$zshenv"
|
|
806
|
-
print_success "Prepended $shim_dir to PATH in .zshenv"
|
|
807
|
-
else
|
|
808
|
-
print_info "$shim_dir already on PATH in .zshenv"
|
|
809
|
-
fi
|
|
810
|
-
fi
|
|
811
|
-
|
|
812
|
-
# Return values via stdout (space-separated)
|
|
813
|
-
echo "$added_to_out $already_in_out"
|
|
814
|
-
return 0
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
# Remove stale old-form PATH entries for the aidevops shim from an rc file.
|
|
818
|
-
# Handles both bash/zsh case-guard form and fish 'contains' form.
|
|
819
|
-
_shellcheck_wrapper_remove_stale_path() {
|
|
820
|
-
local rc_file="$1"
|
|
821
|
-
local is_fish_rc="$2"
|
|
822
|
-
|
|
823
|
-
# Remove stale old-form entries (case guard that only checked presence,
|
|
824
|
-
# not position — left the shim at the end of PATH on upgrades)
|
|
825
|
-
# shellcheck disable=SC2016 # Matching literal $PATH text in rc files, not expanding
|
|
826
|
-
if grep -q 'case ":$PATH:" in.*\.aidevops/bin' "$rc_file"; then
|
|
827
|
-
# shellcheck disable=SC2016
|
|
828
|
-
sed -i.bak '/case ":$PATH:" in.*\.aidevops\/bin/d' "$rc_file"
|
|
829
|
-
rm -f "${rc_file}.bak"
|
|
830
|
-
fi
|
|
831
|
-
# For fish: also remove old 'contains' form that only checked presence
|
|
832
|
-
if [[ "$is_fish_rc" == "true" ]] && grep -q 'contains.*\.aidevops/bin' "$rc_file"; then
|
|
833
|
-
sed -i.bak '/contains.*\.aidevops\/bin/d' "$rc_file"
|
|
834
|
-
rm -f "${rc_file}.bak"
|
|
835
|
-
fi
|
|
836
|
-
|
|
837
|
-
return 0
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
# Configure SHELLCHECK_PATH and PATH shim in a single rc file.
|
|
841
|
-
# Prints "added:<file>" or "already:<file>" to stdout.
|
|
842
|
-
_shellcheck_wrapper_setup_one_rc() {
|
|
843
|
-
local rc_file="$1"
|
|
844
|
-
local env_line="$2"
|
|
845
|
-
local path_line="$3"
|
|
846
|
-
local env_line_fish="$4"
|
|
847
|
-
local path_line_fish="$5"
|
|
848
|
-
|
|
849
|
-
if [[ ! -f "$rc_file" ]]; then
|
|
850
|
-
mkdir -p "$(dirname "$rc_file")"
|
|
851
|
-
touch "$rc_file"
|
|
852
|
-
fi
|
|
853
|
-
|
|
854
|
-
# Detect fish config — uses set -gx syntax, not export
|
|
855
|
-
local is_fish_rc=false
|
|
856
|
-
[[ "$rc_file" == *"/fish/config.fish" ]] && is_fish_rc=true
|
|
857
|
-
|
|
858
|
-
# Select the correct syntax for this shell
|
|
859
|
-
local rc_env_line="$env_line"
|
|
860
|
-
local rc_path_line="$path_line"
|
|
861
|
-
if [[ "$is_fish_rc" == "true" ]]; then
|
|
862
|
-
rc_env_line="$env_line_fish"
|
|
863
|
-
rc_path_line="$path_line_fish"
|
|
864
|
-
fi
|
|
865
|
-
|
|
866
|
-
# SHELLCHECK_PATH env var
|
|
867
|
-
if grep -q 'SHELLCHECK_PATH' "$rc_file"; then
|
|
868
|
-
echo "already:$rc_file"
|
|
869
|
-
else
|
|
870
|
-
{
|
|
871
|
-
echo ""
|
|
872
|
-
echo "# Added by aidevops setup (GH#2915: prevent ShellCheck memory explosion)"
|
|
873
|
-
echo "$rc_env_line"
|
|
874
|
-
} >>"$rc_file"
|
|
875
|
-
echo "added:$rc_file"
|
|
876
|
-
fi
|
|
877
|
-
|
|
878
|
-
# PATH prepend for ~/.aidevops/bin (GH#2993)
|
|
879
|
-
_shellcheck_wrapper_remove_stale_path "$rc_file" "$is_fish_rc"
|
|
880
|
-
# Check for the new sanitize-and-prepend form (uses _aidevops_shim variable)
|
|
881
|
-
if ! grep -Fq '_aidevops_shim' "$rc_file"; then
|
|
882
|
-
{
|
|
883
|
-
echo ""
|
|
884
|
-
echo "# Added by aidevops setup (GH#2993: shellcheck shim on PATH)"
|
|
885
|
-
echo "$rc_path_line"
|
|
886
|
-
} >>"$rc_file"
|
|
887
|
-
fi
|
|
888
|
-
|
|
889
|
-
return 0
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
# Layer 3: Configure SHELLCHECK_PATH and PATH shim in interactive shell rc files.
|
|
893
|
-
_shellcheck_wrapper_setup_rc_files() {
|
|
894
|
-
local env_line="$1"
|
|
895
|
-
local path_line="$2"
|
|
896
|
-
local env_line_fish="$3"
|
|
897
|
-
local path_line_fish="$4"
|
|
898
|
-
local added_to_out=""
|
|
899
|
-
local already_in_out=""
|
|
900
|
-
|
|
901
|
-
local rc_file
|
|
902
|
-
while IFS= read -r rc_file; do
|
|
903
|
-
[[ -z "$rc_file" ]] && continue
|
|
904
|
-
local result
|
|
905
|
-
result=$(_shellcheck_wrapper_setup_one_rc "$rc_file" "$env_line" "$path_line" "$env_line_fish" "$path_line_fish")
|
|
906
|
-
case "$result" in
|
|
907
|
-
added:*) added_to_out="${added_to_out:+$added_to_out, }${result#added:}" ;;
|
|
908
|
-
already:*) already_in_out="${already_in_out:+$already_in_out, }${result#already:}" ;;
|
|
909
|
-
esac
|
|
910
|
-
done < <(get_all_shell_rcs)
|
|
911
|
-
|
|
912
|
-
echo "$added_to_out|$already_in_out"
|
|
913
|
-
return 0
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
# Merge results from zshenv and rc-file layers and print status messages.
|
|
917
|
-
_shellcheck_wrapper_report_results() {
|
|
918
|
-
local env_line="$1"
|
|
919
|
-
local zshenv_result="$2"
|
|
920
|
-
local rc_result="$3"
|
|
921
|
-
|
|
922
|
-
local zshenv_added zshenv_already
|
|
923
|
-
zshenv_added="${zshenv_result%% *}"
|
|
924
|
-
zshenv_already="${zshenv_result##* }"
|
|
925
|
-
|
|
926
|
-
local rc_added rc_already
|
|
927
|
-
rc_added="${rc_result%%|*}"
|
|
928
|
-
rc_already="${rc_result##*|}"
|
|
929
|
-
|
|
930
|
-
# Merge results from layers 2 and 3
|
|
931
|
-
local added_to=""
|
|
932
|
-
local already_in=""
|
|
933
|
-
[[ -n "$zshenv_added" && "$zshenv_added" != " " ]] && added_to="${zshenv_added}"
|
|
934
|
-
[[ -n "$rc_added" ]] && added_to="${added_to:+$added_to, }${rc_added}"
|
|
935
|
-
[[ -n "$zshenv_already" && "$zshenv_already" != " " ]] && already_in="${zshenv_already}"
|
|
936
|
-
[[ -n "$rc_already" ]] && already_in="${already_in:+$already_in, }${rc_already}"
|
|
937
|
-
|
|
938
|
-
if [[ -n "$added_to" ]]; then
|
|
939
|
-
print_success "Configured SHELLCHECK_PATH wrapper in: $added_to"
|
|
940
|
-
fi
|
|
941
|
-
|
|
942
|
-
if [[ -n "$already_in" ]]; then
|
|
943
|
-
print_info "SHELLCHECK_PATH already configured in: $already_in"
|
|
944
|
-
fi
|
|
945
|
-
|
|
946
|
-
if [[ -z "$added_to" && -z "$already_in" && "$PLATFORM_MACOS" != "true" ]]; then
|
|
947
|
-
print_warning "Could not configure SHELLCHECK_PATH automatically"
|
|
948
|
-
print_info "Add this to your shell config: $env_line"
|
|
949
|
-
fi
|
|
950
|
-
|
|
951
|
-
return 0
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
setup_shellcheck_wrapper() {
|
|
955
|
-
local wrapper_path="$HOME/.aidevops/agents/scripts/shellcheck-wrapper.sh"
|
|
956
|
-
|
|
957
|
-
_shellcheck_wrapper_verify "$wrapper_path" || return 0
|
|
958
|
-
|
|
959
|
-
local env_line
|
|
960
|
-
# shellcheck disable=SC2016 # env_line is written to rc files; must expand at shell startup
|
|
961
|
-
env_line='export SHELLCHECK_PATH="$HOME/.aidevops/agents/scripts/shellcheck-wrapper.sh"'
|
|
962
|
-
# shellcheck disable=SC2016 # path_line is written to rc files; must expand at shell startup
|
|
963
|
-
# Sanitize-and-prepend: strip any existing occurrence of the shim dir from PATH
|
|
964
|
-
# (it may be at the END from a previous setup run), then prepend it. This ensures
|
|
965
|
-
# the shim is always first, even on machines upgrading from the old append form.
|
|
966
|
-
# The ${PATH:+:$PATH} guard handles the empty-PATH edge case without a trailing colon.
|
|
967
|
-
local path_line='_aidevops_shim="$HOME/.aidevops/bin"; PATH="$(printf '\''%s'\'' "$PATH" | tr '\'':'\'' '\''\n'\'' | grep -Fxv -- "$_aidevops_shim" | paste -sd: -)"; export PATH="$_aidevops_shim${PATH:+:$PATH}"; unset _aidevops_shim'
|
|
968
|
-
# Fish shell uses different syntax (set -gx instead of export)
|
|
969
|
-
# shellcheck disable=SC2016 # fish lines are written to config.fish; must expand at shell startup
|
|
970
|
-
local env_line_fish='set -gx SHELLCHECK_PATH "$HOME/.aidevops/agents/scripts/shellcheck-wrapper.sh"'
|
|
971
|
-
# shellcheck disable=SC2016 # fish path line: strip existing, then prepend
|
|
972
|
-
local path_line_fish='set -l _aidevops_shim "$HOME/.aidevops/bin"; set -l _aidevops_rest (string match -v -- "$_aidevops_shim" $PATH); set -gx PATH $_aidevops_shim $_aidevops_rest'
|
|
973
|
-
|
|
974
|
-
local shim_dir="$HOME/.aidevops/bin"
|
|
975
|
-
|
|
976
|
-
# Layer 0: PATH shim (GH#2993)
|
|
977
|
-
_shellcheck_wrapper_setup_shim "$wrapper_path"
|
|
978
|
-
|
|
979
|
-
# Layer 1: launchctl setenv (macOS) — GUI-launched processes
|
|
980
|
-
if [[ "$PLATFORM_MACOS" == "true" ]]; then
|
|
981
|
-
_shellcheck_wrapper_setup_launchctl "$wrapper_path" "$shim_dir"
|
|
982
|
-
fi
|
|
983
|
-
|
|
984
|
-
# Layer 2: .zshenv — ALL zsh processes (interactive AND non-interactive)
|
|
985
|
-
local zshenv_result
|
|
986
|
-
zshenv_result=$(_shellcheck_wrapper_setup_zshenv "$env_line" "$path_line" "$shim_dir")
|
|
987
|
-
|
|
988
|
-
# Layer 3: Shell rc files — interactive terminal sessions
|
|
989
|
-
local rc_result
|
|
990
|
-
rc_result=$(_shellcheck_wrapper_setup_rc_files "$env_line" "$path_line" "$env_line_fish" "$path_line_fish")
|
|
991
|
-
|
|
992
|
-
# Report merged results from layers 2 and 3
|
|
993
|
-
_shellcheck_wrapper_report_results "$env_line" "$zshenv_result" "$rc_result"
|
|
994
|
-
|
|
995
|
-
# Also export for current session
|
|
996
|
-
export SHELLCHECK_PATH="$wrapper_path"
|
|
997
|
-
export PATH="$HOME/.aidevops/bin:$PATH"
|
|
998
|
-
|
|
999
|
-
return 0
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
# Check whether server access aliases are already configured in any rc file.
|
|
1003
|
-
# Returns 0 (true) if already configured, 1 (false) if not.
|
|
1004
|
-
_aliases_check_configured() {
|
|
1005
|
-
local rc_file
|
|
1006
|
-
while IFS= read -r rc_file; do
|
|
1007
|
-
[[ -z "$rc_file" ]] && continue
|
|
1008
|
-
if [[ -f "$rc_file" ]] && grep -q "# AI Assistant Server Access" "$rc_file"; then
|
|
1009
|
-
return 0
|
|
1010
|
-
fi
|
|
1011
|
-
done < <(get_all_shell_rcs)
|
|
1012
|
-
|
|
1013
|
-
# Also check fish config (not included in get_all_shell_rcs on macOS)
|
|
1014
|
-
local fish_config="$HOME/.config/fish/config.fish"
|
|
1015
|
-
if [[ -f "$fish_config" ]] && grep -q "# AI Assistant Server Access" "$fish_config"; then
|
|
1016
|
-
return 0
|
|
1017
|
-
fi
|
|
1018
|
-
|
|
1019
|
-
return 1
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
# Replace the aidevops alias block in a single rc file.
|
|
1023
|
-
# Removes the old block (marker line through the next blank line) and appends
|
|
1024
|
-
# the new block. Idempotent: safe to call on every setup run.
|
|
1025
|
-
_aliases_replace_in_file() {
|
|
1026
|
-
local rc_file="$1"
|
|
1027
|
-
local alias_block="$2"
|
|
1028
|
-
local marker="# AI Assistant Server Access"
|
|
1029
|
-
local tmp_file
|
|
1030
|
-
tmp_file=$(mktemp "${TMPDIR:-/tmp}/aidevops-aliases-XXXXXX") || return 1
|
|
1031
|
-
|
|
1032
|
-
# Strip existing block: from marker line to the next blank line (inclusive)
|
|
1033
|
-
awk -v marker="$marker" '
|
|
1034
|
-
$0 ~ marker { in_block=1; next }
|
|
1035
|
-
in_block && /^[[:space:]]*$/ { in_block=0; next }
|
|
1036
|
-
in_block { next }
|
|
1037
|
-
{ print }
|
|
1038
|
-
' "$rc_file" >"$tmp_file" && mv "$tmp_file" "$rc_file"
|
|
1039
|
-
|
|
1040
|
-
# Append updated block
|
|
1041
|
-
printf '%s\n' "$alias_block" >>"$rc_file"
|
|
1042
|
-
return 0
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
# Write alias blocks to fish or bash/zsh rc files.
|
|
1046
|
-
# Always replaces an existing aidevops alias block so updates propagate.
|
|
1047
|
-
# Prints the list of files aliases were added/updated in (comma-separated).
|
|
1048
|
-
_aliases_write_to_rc_files() {
|
|
1049
|
-
local is_fish="$1"
|
|
1050
|
-
local alias_block_bash="$2"
|
|
1051
|
-
local alias_block_fish="$3"
|
|
1052
|
-
local added_to=""
|
|
1053
|
-
|
|
1054
|
-
# Handle fish separately
|
|
1055
|
-
if [[ "$is_fish" == "true" ]]; then
|
|
1056
|
-
local fish_rc="$HOME/.config/fish/config.fish"
|
|
1057
|
-
mkdir -p "$HOME/.config/fish"
|
|
1058
|
-
if [[ ! -f "$fish_rc" ]]; then
|
|
1059
|
-
touch "$fish_rc"
|
|
1060
|
-
fi
|
|
1061
|
-
_aliases_replace_in_file "$fish_rc" "$alias_block_fish"
|
|
1062
|
-
added_to="$fish_rc"
|
|
1063
|
-
else
|
|
1064
|
-
# Add/update in all bash/zsh rc files
|
|
1065
|
-
local rc_file
|
|
1066
|
-
while IFS= read -r rc_file; do
|
|
1067
|
-
[[ -z "$rc_file" ]] && continue
|
|
1068
|
-
|
|
1069
|
-
# Create if it doesn't exist
|
|
1070
|
-
if [[ ! -f "$rc_file" ]]; then
|
|
1071
|
-
touch "$rc_file"
|
|
1072
|
-
fi
|
|
1073
|
-
|
|
1074
|
-
_aliases_replace_in_file "$rc_file" "$alias_block_bash"
|
|
1075
|
-
added_to="${added_to:+$added_to, }$rc_file"
|
|
1076
|
-
done < <(get_all_shell_rcs)
|
|
1077
|
-
fi
|
|
1078
|
-
|
|
1079
|
-
echo "$added_to"
|
|
1080
|
-
return 0
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
# Build the bash/zsh and fish alias blocks for server access.
|
|
1084
|
-
# Prints two lines: "bash:<block>" and "fish:<block>" — callers split on newline.
|
|
1085
|
-
# Since blocks are multi-line, we use process substitution via temp files.
|
|
1086
|
-
# Outputs bash block to stdout, fish block to fd3 (caller must set up fd3).
|
|
1087
|
-
_aliases_build_blocks() {
|
|
1088
|
-
cat <<'ALIASES'
|
|
1089
|
-
|
|
1090
|
-
# AI Assistant Server Access Framework
|
|
1091
|
-
alias servers='./.agents/scripts/servers-helper.sh'
|
|
1092
|
-
alias servers-list='./.agents/scripts/servers-helper.sh list'
|
|
1093
|
-
alias hostinger='./.agents/scripts/hostinger-helper.sh'
|
|
1094
|
-
alias hetzner='./.agents/scripts/hetzner-helper.sh'
|
|
1095
|
-
alias aws-helper='./.agents/scripts/aws-helper.sh'
|
|
1096
|
-
# Claude Code: skip interactive permission prompts (safe for personal machines)
|
|
1097
|
-
command -v claude >/dev/null 2>&1 && alias claude='claude --dangerously-skip-permissions'
|
|
1098
|
-
ALIASES
|
|
1099
|
-
return 0
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
# Build the fish-syntax alias block for server access.
|
|
1103
|
-
_aliases_build_fish_block() {
|
|
1104
|
-
cat <<'ALIASES'
|
|
1105
|
-
|
|
1106
|
-
# AI Assistant Server Access Framework
|
|
1107
|
-
alias servers './.agents/scripts/servers-helper.sh'
|
|
1108
|
-
alias servers-list './.agents/scripts/servers-helper.sh list'
|
|
1109
|
-
alias hostinger './.agents/scripts/hostinger-helper.sh'
|
|
1110
|
-
alias hetzner './.agents/scripts/hetzner-helper.sh'
|
|
1111
|
-
alias aws-helper './.agents/scripts/aws-helper.sh'
|
|
1112
|
-
# Claude Code: skip interactive permission prompts (safe for personal machines)
|
|
1113
|
-
if command -v claude >/dev/null 2>&1; alias claude 'claude --dangerously-skip-permissions'; end
|
|
1114
|
-
ALIASES
|
|
1115
|
-
return 0
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
# Add server access aliases to shell rc files (bash/zsh/fish)
|
|
1119
|
-
setup_aliases() {
|
|
1120
|
-
print_info "Setting up shell aliases..."
|
|
1121
|
-
|
|
1122
|
-
local default_shell
|
|
1123
|
-
default_shell=$(detect_default_shell)
|
|
1124
|
-
|
|
1125
|
-
# Fish shell uses different alias syntax
|
|
1126
|
-
local is_fish=false
|
|
1127
|
-
[[ "$default_shell" == "fish" ]] && is_fish=true
|
|
1128
|
-
|
|
1129
|
-
local alias_block_bash
|
|
1130
|
-
alias_block_bash=$(_aliases_build_blocks)
|
|
1131
|
-
|
|
1132
|
-
local alias_block_fish
|
|
1133
|
-
alias_block_fish=$(_aliases_build_fish_block)
|
|
1134
|
-
|
|
1135
|
-
print_info "Detected default shell: $default_shell"
|
|
1136
|
-
setup_prompt add_aliases "Add shell aliases? [Y/n]: " "Y"
|
|
1137
|
-
|
|
1138
|
-
if [[ "$add_aliases" =~ ^[Yy]?$ ]]; then
|
|
1139
|
-
local added_to
|
|
1140
|
-
added_to=$(_aliases_write_to_rc_files "$is_fish" "$alias_block_bash" "$alias_block_fish")
|
|
1141
|
-
|
|
1142
|
-
if [[ -n "$added_to" ]]; then
|
|
1143
|
-
print_success "Aliases added to: $added_to"
|
|
1144
|
-
print_info "Restart your terminal to use aliases"
|
|
1145
|
-
fi
|
|
1146
|
-
else
|
|
1147
|
-
print_info "Skipped alias setup by user request"
|
|
1148
|
-
fi
|
|
1149
|
-
return 0
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
# Check if terminal title integration is already configured in any rc file.
|
|
1153
|
-
# Returns 0 if configured, 1 if not.
|
|
1154
|
-
_terminal_title_is_configured() {
|
|
1155
|
-
local rc_file
|
|
1156
|
-
while IFS= read -r rc_file; do
|
|
1157
|
-
[[ -z "$rc_file" ]] && continue
|
|
1158
|
-
if [[ -f "$rc_file" ]] && grep -q "aidevops terminal-title" "$rc_file"; then
|
|
1159
|
-
return 0
|
|
1160
|
-
fi
|
|
1161
|
-
done < <(get_all_shell_rcs)
|
|
1162
|
-
return 1
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
# Print current shell and Tabby status for terminal title setup.
|
|
1166
|
-
_terminal_title_show_status() {
|
|
1167
|
-
echo ""
|
|
1168
|
-
print_info "Terminal title integration syncs your terminal tab with git repo/branch"
|
|
1169
|
-
print_info "Example: Tab shows 'aidevops/feature/xyz' when in that branch"
|
|
1170
|
-
echo ""
|
|
1171
|
-
echo "Current status:"
|
|
1172
|
-
|
|
1173
|
-
local shell_name
|
|
1174
|
-
shell_name=$(detect_default_shell)
|
|
1175
|
-
local shell_info="$shell_name"
|
|
1176
|
-
if [[ "$shell_name" == "zsh" ]] && [[ -d "$HOME/.oh-my-zsh" ]]; then
|
|
1177
|
-
shell_info="$shell_name (Oh-My-Zsh)"
|
|
1178
|
-
fi
|
|
1179
|
-
echo " Shell: $shell_info"
|
|
1180
|
-
|
|
1181
|
-
local tabby_config="$HOME/Library/Application Support/tabby/config.yaml"
|
|
1182
|
-
if [[ -f "$tabby_config" ]]; then
|
|
1183
|
-
local disabled_count
|
|
1184
|
-
# grep -c exits 1 on no match; || : inside subshell prevents ERR trap noise
|
|
1185
|
-
disabled_count=$(grep -c "disableDynamicTitle: true" "$tabby_config" || :)
|
|
1186
|
-
if [[ "${disabled_count:-0}" -gt 0 ]]; then
|
|
1187
|
-
echo " Tabby: detected, dynamic titles disabled in $disabled_count profile(s) (will fix)"
|
|
1188
|
-
else
|
|
1189
|
-
echo " Tabby: detected, dynamic titles enabled"
|
|
1190
|
-
fi
|
|
1191
|
-
fi
|
|
1192
|
-
|
|
1193
|
-
return 0
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
# Prompt the user and run the terminal title installer.
|
|
1197
|
-
_terminal_title_prompt_and_install() {
|
|
1198
|
-
local setup_script="$1"
|
|
1199
|
-
|
|
1200
|
-
echo ""
|
|
1201
|
-
setup_prompt install_title "Install terminal title integration? [Y/n]: " "Y"
|
|
1202
|
-
|
|
1203
|
-
if [[ "$install_title" =~ ^[Yy]?$ ]]; then
|
|
1204
|
-
if bash "$setup_script" install; then
|
|
1205
|
-
print_success "Terminal title integration installed"
|
|
1206
|
-
else
|
|
1207
|
-
print_warning "Terminal title setup encountered issues (non-critical)"
|
|
1208
|
-
fi
|
|
1209
|
-
else
|
|
1210
|
-
print_info "Skipped terminal title setup by user request"
|
|
1211
|
-
print_info "You can install later with: ~/.aidevops/agents/scripts/terminal-title-setup.sh install"
|
|
1212
|
-
fi
|
|
1213
|
-
|
|
1214
|
-
return 0
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
# Install terminal title integration that syncs tab titles with git repo/branch
|
|
1218
|
-
setup_terminal_title() {
|
|
1219
|
-
# Check prerequisites before announcing setup (GH#5240)
|
|
1220
|
-
local setup_script=".agents/scripts/terminal-title-setup.sh"
|
|
1221
|
-
|
|
1222
|
-
if [[ ! -f "$setup_script" ]]; then
|
|
1223
|
-
print_skip "Terminal title" "setup script not found" "Deploy agents first (setup.sh), then re-run"
|
|
1224
|
-
setup_track_skipped "Terminal title" "setup script not found"
|
|
1225
|
-
return 0
|
|
1226
|
-
fi
|
|
1227
|
-
|
|
1228
|
-
if _terminal_title_is_configured; then
|
|
1229
|
-
print_success "Terminal title integration already configured"
|
|
1230
|
-
setup_track_configured "Terminal title"
|
|
1231
|
-
return 0
|
|
1232
|
-
fi
|
|
1233
|
-
|
|
1234
|
-
# Prerequisites met — proceed with setup
|
|
1235
|
-
print_info "Setting up terminal title integration..."
|
|
1236
|
-
_terminal_title_show_status
|
|
1237
|
-
_terminal_title_prompt_and_install "$setup_script"
|
|
1238
|
-
|
|
1239
|
-
return 0
|
|
1240
|
-
}
|