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
package/setup-modules/core.sh
DELETED
|
@@ -1,736 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
# SPDX-FileCopyrightText: 2025-2026 Marcus Quinn
|
|
4
|
-
# Core setup functions: requirements, permissions, location
|
|
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
|
-
# Install aidevops inside an OrbStack Linux VM (macOS only, user chose option 2)
|
|
15
|
-
_bootstrap_orbstack_install() {
|
|
16
|
-
# Install OrbStack if not present
|
|
17
|
-
if ! command -v orb >/dev/null 2>&1 && [[ ! -d "/Applications/OrbStack.app" ]]; then
|
|
18
|
-
if command -v brew >/dev/null 2>&1; then
|
|
19
|
-
print_info "Installing OrbStack via Homebrew..."
|
|
20
|
-
brew install --cask orbstack
|
|
21
|
-
else
|
|
22
|
-
print_error "Homebrew is required to install OrbStack"
|
|
23
|
-
echo "Install Homebrew first: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
|
24
|
-
echo "Then re-run this installer."
|
|
25
|
-
exit 1
|
|
26
|
-
fi
|
|
27
|
-
fi
|
|
28
|
-
|
|
29
|
-
# Wait for OrbStack to be ready
|
|
30
|
-
if ! command -v orb >/dev/null 2>&1; then
|
|
31
|
-
print_info "Waiting for OrbStack CLI to become available..."
|
|
32
|
-
# OrbStack installs the CLI at /usr/local/bin/orb
|
|
33
|
-
local wait_count=0
|
|
34
|
-
while ! command -v orb >/dev/null 2>&1 && [[ $wait_count -lt 30 ]]; do
|
|
35
|
-
sleep 2
|
|
36
|
-
((++wait_count))
|
|
37
|
-
done
|
|
38
|
-
if ! command -v orb >/dev/null 2>&1; then
|
|
39
|
-
print_error "OrbStack CLI not found after installation"
|
|
40
|
-
echo "Open OrbStack.app manually, then re-run this installer."
|
|
41
|
-
exit 1
|
|
42
|
-
fi
|
|
43
|
-
fi
|
|
44
|
-
|
|
45
|
-
# Create or use existing Ubuntu VM
|
|
46
|
-
local vm_name="aidevops"
|
|
47
|
-
if orb list 2>/dev/null | grep -qxF "$vm_name"; then
|
|
48
|
-
print_info "Using existing OrbStack VM: $vm_name"
|
|
49
|
-
else
|
|
50
|
-
print_info "Creating Ubuntu VM: $vm_name..."
|
|
51
|
-
orb create ubuntu "$vm_name"
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
# Run the installer inside the VM
|
|
55
|
-
print_info "Installing aidevops inside the VM..."
|
|
56
|
-
echo ""
|
|
57
|
-
orb run -m "$vm_name" bash -c 'bash <(curl -fsSL https://aidevops.sh/install)'
|
|
58
|
-
|
|
59
|
-
echo ""
|
|
60
|
-
print_success "aidevops installed in OrbStack VM: $vm_name"
|
|
61
|
-
echo ""
|
|
62
|
-
echo "To use aidevops in the VM:"
|
|
63
|
-
echo " orb shell $vm_name # Enter the VM"
|
|
64
|
-
echo " orb run -m $vm_name opencode # Run OpenCode directly"
|
|
65
|
-
echo ""
|
|
66
|
-
exit 0
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
# Auto-install git using the available package manager
|
|
70
|
-
_bootstrap_install_git() {
|
|
71
|
-
print_warning "git is required but not installed - attempting auto-install..."
|
|
72
|
-
if [[ "$(uname)" == "Darwin" ]]; then
|
|
73
|
-
# macOS: xcode-select --install triggers git install
|
|
74
|
-
print_info "Installing Xcode Command Line Tools (includes git)..."
|
|
75
|
-
if xcode-select --install 2>/dev/null; then
|
|
76
|
-
# Wait for installation to complete (timeout after 5 minutes)
|
|
77
|
-
print_info "Waiting for Xcode CLT installation to complete (timeout: 5m)..."
|
|
78
|
-
local xcode_wait=0
|
|
79
|
-
local xcode_max_wait=300
|
|
80
|
-
until command -v git >/dev/null 2>&1; do
|
|
81
|
-
sleep 5
|
|
82
|
-
xcode_wait=$((xcode_wait + 5))
|
|
83
|
-
if [[ $xcode_wait -ge $xcode_max_wait ]]; then
|
|
84
|
-
print_error "Timed out waiting for Xcode CLT installation after ${xcode_max_wait}s"
|
|
85
|
-
echo "Complete the installation manually, then re-run this installer."
|
|
86
|
-
exit 1
|
|
87
|
-
fi
|
|
88
|
-
done
|
|
89
|
-
print_success "git installed via Xcode Command Line Tools"
|
|
90
|
-
else
|
|
91
|
-
# Already installed or failed
|
|
92
|
-
if ! command -v git >/dev/null 2>&1; then
|
|
93
|
-
print_error "git installation failed"
|
|
94
|
-
echo "Install git manually: brew install git (macOS)"
|
|
95
|
-
exit 1
|
|
96
|
-
fi
|
|
97
|
-
fi
|
|
98
|
-
elif command -v apt-get >/dev/null 2>&1; then
|
|
99
|
-
print_info "Installing git via apt..."
|
|
100
|
-
sudo apt-get update -qq && sudo apt-get install -y -qq git
|
|
101
|
-
if ! command -v git >/dev/null 2>&1; then
|
|
102
|
-
print_error "git installation failed"
|
|
103
|
-
exit 1
|
|
104
|
-
fi
|
|
105
|
-
print_success "git installed"
|
|
106
|
-
elif command -v dnf >/dev/null 2>&1; then
|
|
107
|
-
print_info "Installing git via dnf..."
|
|
108
|
-
sudo dnf install -y git
|
|
109
|
-
if ! command -v git >/dev/null 2>&1; then
|
|
110
|
-
print_error "git installation failed"
|
|
111
|
-
exit 1
|
|
112
|
-
fi
|
|
113
|
-
print_success "git installed"
|
|
114
|
-
elif command -v yum >/dev/null 2>&1; then
|
|
115
|
-
print_info "Installing git via yum..."
|
|
116
|
-
sudo yum install -y git
|
|
117
|
-
if ! command -v git >/dev/null 2>&1; then
|
|
118
|
-
print_error "git installation failed"
|
|
119
|
-
exit 1
|
|
120
|
-
fi
|
|
121
|
-
print_success "git installed"
|
|
122
|
-
elif command -v pacman >/dev/null 2>&1; then
|
|
123
|
-
print_info "Installing git via pacman..."
|
|
124
|
-
sudo pacman -S --noconfirm git
|
|
125
|
-
if ! command -v git >/dev/null 2>&1; then
|
|
126
|
-
print_error "git installation failed"
|
|
127
|
-
exit 1
|
|
128
|
-
fi
|
|
129
|
-
print_success "git installed"
|
|
130
|
-
elif command -v apk >/dev/null 2>&1; then
|
|
131
|
-
print_info "Installing git via apk..."
|
|
132
|
-
sudo apk add git
|
|
133
|
-
if ! command -v git >/dev/null 2>&1; then
|
|
134
|
-
print_error "git installation failed"
|
|
135
|
-
exit 1
|
|
136
|
-
fi
|
|
137
|
-
print_success "git installed"
|
|
138
|
-
else
|
|
139
|
-
print_error "git is required but not installed and no supported package manager found"
|
|
140
|
-
echo "Install git manually and re-run the installer"
|
|
141
|
-
exit 1
|
|
142
|
-
fi
|
|
143
|
-
return 0
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
bootstrap_repo() {
|
|
147
|
-
# Detect if running from curl (no script directory context)
|
|
148
|
-
local script_path="${BASH_SOURCE[0]}"
|
|
149
|
-
|
|
150
|
-
# If script_path is empty, stdin, bash, or /dev/fd/* (process substitution), we're running from curl
|
|
151
|
-
# bash <(curl ...) produces paths like /dev/fd/63
|
|
152
|
-
if [[ -z "$script_path" || "$script_path" == "/dev/stdin" || "$script_path" == "bash" || "$script_path" == /dev/fd/* ]]; then
|
|
153
|
-
print_info "Remote install detected - bootstrapping repository..."
|
|
154
|
-
|
|
155
|
-
# On macOS, offer choice: install locally or in an OrbStack VM
|
|
156
|
-
# Skip prompt in non-interactive mode (parse_args hasn't run yet,
|
|
157
|
-
# so check $@ directly for --non-interactive/-n flags)
|
|
158
|
-
local _bootstrap_non_interactive=false
|
|
159
|
-
local _arg
|
|
160
|
-
for _arg in "$@"; do
|
|
161
|
-
case "$_arg" in
|
|
162
|
-
--non-interactive | -n) _bootstrap_non_interactive=true ;;
|
|
163
|
-
esac
|
|
164
|
-
done
|
|
165
|
-
[[ "${AIDEVOPS_NON_INTERACTIVE:-false}" == "true" ]] && _bootstrap_non_interactive=true
|
|
166
|
-
[[ ! -t 0 ]] && _bootstrap_non_interactive=true
|
|
167
|
-
|
|
168
|
-
if [[ "$(uname)" == "Darwin" && "$_bootstrap_non_interactive" == "false" ]]; then
|
|
169
|
-
echo ""
|
|
170
|
-
echo "Where would you like to install aidevops?"
|
|
171
|
-
echo ""
|
|
172
|
-
echo " 1) Install on this Mac (recommended)"
|
|
173
|
-
echo " 2) Install in a Linux VM (via OrbStack)"
|
|
174
|
-
echo ""
|
|
175
|
-
# Cannot use setup_prompt here — _common.sh not yet sourced during bootstrap.
|
|
176
|
-
# The _bootstrap_non_interactive guard above prevents reaching this line.
|
|
177
|
-
local install_target=""
|
|
178
|
-
read -r -p "Choose [1/2] (default: 1): " install_target || install_target="1"
|
|
179
|
-
|
|
180
|
-
if [[ "$install_target" == "2" ]]; then
|
|
181
|
-
print_info "Setting up OrbStack VM installation..."
|
|
182
|
-
_bootstrap_orbstack_install
|
|
183
|
-
fi
|
|
184
|
-
fi
|
|
185
|
-
|
|
186
|
-
# Auto-install git if missing (required for cloning)
|
|
187
|
-
if ! command -v git >/dev/null 2>&1; then
|
|
188
|
-
_bootstrap_install_git
|
|
189
|
-
fi
|
|
190
|
-
|
|
191
|
-
# Create parent directory
|
|
192
|
-
mkdir -p "$(dirname "$INSTALL_DIR")"
|
|
193
|
-
|
|
194
|
-
if [[ -d "$INSTALL_DIR/.git" ]]; then
|
|
195
|
-
print_info "Existing installation found - updating..."
|
|
196
|
-
cd "$INSTALL_DIR" || exit 1
|
|
197
|
-
if ! git pull --ff-only; then
|
|
198
|
-
print_warning "Git pull failed - trying reset to origin/main"
|
|
199
|
-
git fetch origin
|
|
200
|
-
git reset --hard origin/main
|
|
201
|
-
fi
|
|
202
|
-
else
|
|
203
|
-
print_info "Cloning aidevops to $INSTALL_DIR..."
|
|
204
|
-
if [[ -d "$INSTALL_DIR" ]]; then
|
|
205
|
-
print_warning "Directory exists but is not a git repo - backing up"
|
|
206
|
-
mv "$INSTALL_DIR" "$INSTALL_DIR.backup.$(date +%Y%m%d_%H%M%S)"
|
|
207
|
-
fi
|
|
208
|
-
if ! git clone "$REPO_URL" "$INSTALL_DIR"; then
|
|
209
|
-
print_error "Failed to clone repository"
|
|
210
|
-
exit 1
|
|
211
|
-
fi
|
|
212
|
-
fi
|
|
213
|
-
|
|
214
|
-
print_success "Repository ready at $INSTALL_DIR"
|
|
215
|
-
|
|
216
|
-
# Re-execute the local script
|
|
217
|
-
cd "$INSTALL_DIR" || exit 1
|
|
218
|
-
exec bash "./setup.sh" "$@"
|
|
219
|
-
fi
|
|
220
|
-
return 0
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
# Detect package manager
|
|
224
|
-
detect_package_manager() {
|
|
225
|
-
if command -v brew >/dev/null 2>&1; then
|
|
226
|
-
echo "brew"
|
|
227
|
-
elif command -v apt-get >/dev/null 2>&1; then
|
|
228
|
-
echo "apt"
|
|
229
|
-
elif command -v dnf >/dev/null 2>&1; then
|
|
230
|
-
echo "dnf"
|
|
231
|
-
elif command -v yum >/dev/null 2>&1; then
|
|
232
|
-
echo "yum"
|
|
233
|
-
elif command -v pacman >/dev/null 2>&1; then
|
|
234
|
-
echo "pacman"
|
|
235
|
-
elif command -v apk >/dev/null 2>&1; then
|
|
236
|
-
echo "apk"
|
|
237
|
-
else
|
|
238
|
-
echo "unknown"
|
|
239
|
-
fi
|
|
240
|
-
return 0
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
# Install packages using detected package manager
|
|
244
|
-
# For Homebrew: runs 'brew update' with a spinner first (can take 30s+),
|
|
245
|
-
# then installs packages with HOMEBREW_NO_AUTO_UPDATE to avoid a second update.
|
|
246
|
-
install_packages() {
|
|
247
|
-
local pkg_manager="$1"
|
|
248
|
-
shift
|
|
249
|
-
local packages=("$@")
|
|
250
|
-
|
|
251
|
-
# Cache sudo credentials before spinner commands.
|
|
252
|
-
# Backgrounded processes cannot safely prompt for passwords.
|
|
253
|
-
if [[ "$pkg_manager" =~ ^(apt|dnf|yum|pacman|apk)$ ]]; then
|
|
254
|
-
sudo -v
|
|
255
|
-
fi
|
|
256
|
-
|
|
257
|
-
case "$pkg_manager" in
|
|
258
|
-
brew)
|
|
259
|
-
# Run brew update with spinner (Homebrew auto-update is slow and silent)
|
|
260
|
-
if ! run_with_spinner "Updating Homebrew" brew update; then
|
|
261
|
-
print_error "Homebrew update failed"
|
|
262
|
-
return 1
|
|
263
|
-
fi
|
|
264
|
-
# Install with auto-update disabled (we just ran it)
|
|
265
|
-
# Note: run_with_spinner auto-exports HOMEBREW_NO_AUTO_UPDATE for brew commands
|
|
266
|
-
run_with_spinner "Installing ${packages[*]}" brew install "${packages[@]}"
|
|
267
|
-
;;
|
|
268
|
-
apt)
|
|
269
|
-
if ! run_with_spinner "Updating package lists" sudo apt-get update -qq; then
|
|
270
|
-
print_error "apt-get update failed"
|
|
271
|
-
return 1
|
|
272
|
-
fi
|
|
273
|
-
run_with_spinner "Installing ${packages[*]}" sudo apt-get install -y -qq "${packages[@]}"
|
|
274
|
-
;;
|
|
275
|
-
dnf)
|
|
276
|
-
run_with_spinner "Installing ${packages[*]}" sudo dnf install -y "${packages[@]}"
|
|
277
|
-
;;
|
|
278
|
-
yum)
|
|
279
|
-
run_with_spinner "Installing ${packages[*]}" sudo yum install -y "${packages[@]}"
|
|
280
|
-
;;
|
|
281
|
-
pacman)
|
|
282
|
-
run_with_spinner "Installing ${packages[*]}" sudo pacman -S --noconfirm "${packages[@]}"
|
|
283
|
-
;;
|
|
284
|
-
apk)
|
|
285
|
-
run_with_spinner "Installing ${packages[*]}" sudo apk add "${packages[@]}"
|
|
286
|
-
;;
|
|
287
|
-
*)
|
|
288
|
-
return 1
|
|
289
|
-
;;
|
|
290
|
-
esac
|
|
291
|
-
|
|
292
|
-
return 0
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
# Offer to install Homebrew (Linuxbrew) on Linux when brew is not available
|
|
296
|
-
# Many tools in the aidevops ecosystem (Beads, Worktrunk, bv) are distributed
|
|
297
|
-
# via Homebrew taps. On macOS, brew is almost always present. On Linux, this
|
|
298
|
-
# function offers to install it so those tools can be installed automatically.
|
|
299
|
-
# Returns: 0 if brew is now available, 1 if user declined or install failed
|
|
300
|
-
ensure_homebrew() {
|
|
301
|
-
# Already available
|
|
302
|
-
if command -v brew &>/dev/null; then
|
|
303
|
-
return 0
|
|
304
|
-
fi
|
|
305
|
-
|
|
306
|
-
# Only offer on Linux (macOS users should install Homebrew themselves)
|
|
307
|
-
if [[ "$(uname)" == "Darwin" ]]; then
|
|
308
|
-
print_warning "Homebrew not found. Install from https://brew.sh"
|
|
309
|
-
return 1
|
|
310
|
-
fi
|
|
311
|
-
|
|
312
|
-
# Non-interactive mode: skip
|
|
313
|
-
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
314
|
-
return 1
|
|
315
|
-
fi
|
|
316
|
-
|
|
317
|
-
echo ""
|
|
318
|
-
print_info "Homebrew (Linuxbrew) is not installed."
|
|
319
|
-
print_info "Several optional tools (Beads CLI, Worktrunk, bv) install via Homebrew taps."
|
|
320
|
-
echo ""
|
|
321
|
-
local install_brew="Y"
|
|
322
|
-
setup_prompt install_brew "Install Homebrew for Linux? [Y/n]: " "Y"
|
|
323
|
-
|
|
324
|
-
if [[ ! "$install_brew" =~ ^[Yy]?$ ]]; then
|
|
325
|
-
print_info "Skipped Homebrew installation"
|
|
326
|
-
return 1
|
|
327
|
-
fi
|
|
328
|
-
|
|
329
|
-
print_info "Installing Homebrew (Linuxbrew)..."
|
|
330
|
-
|
|
331
|
-
# Prerequisites for Linuxbrew
|
|
332
|
-
if command -v apt-get &>/dev/null; then
|
|
333
|
-
sudo apt-get update -qq
|
|
334
|
-
sudo apt-get install -y -qq build-essential procps curl file git
|
|
335
|
-
elif command -v dnf &>/dev/null; then
|
|
336
|
-
sudo dnf groupinstall -y 'Development Tools'
|
|
337
|
-
sudo dnf install -y procps-ng curl file git
|
|
338
|
-
elif command -v yum &>/dev/null; then
|
|
339
|
-
sudo yum groupinstall -y 'Development Tools'
|
|
340
|
-
sudo yum install -y procps-ng curl file git
|
|
341
|
-
fi
|
|
342
|
-
|
|
343
|
-
# Install Homebrew using verified_install pattern
|
|
344
|
-
if verified_install "Homebrew" "https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh"; then
|
|
345
|
-
# Add Homebrew to PATH for this session
|
|
346
|
-
local brew_prefix="/home/linuxbrew/.linuxbrew"
|
|
347
|
-
if [[ -x "$brew_prefix/bin/brew" ]]; then
|
|
348
|
-
eval "$("$brew_prefix/bin/brew" shellenv)"
|
|
349
|
-
fi
|
|
350
|
-
|
|
351
|
-
# Persist to shell rc files
|
|
352
|
-
local brew_line="eval \"\$($brew_prefix/bin/brew shellenv)\""
|
|
353
|
-
local rc_file
|
|
354
|
-
while IFS= read -r rc_file; do
|
|
355
|
-
[[ -z "$rc_file" ]] && continue
|
|
356
|
-
if ! grep -q 'linuxbrew' "$rc_file" 2>/dev/null; then
|
|
357
|
-
{
|
|
358
|
-
echo ""
|
|
359
|
-
echo "# Homebrew (Linuxbrew) - added by aidevops setup"
|
|
360
|
-
echo "$brew_line"
|
|
361
|
-
} >>"$rc_file"
|
|
362
|
-
fi
|
|
363
|
-
done < <(get_all_shell_rcs)
|
|
364
|
-
|
|
365
|
-
if command -v brew &>/dev/null; then
|
|
366
|
-
print_success "Homebrew installed and added to PATH"
|
|
367
|
-
return 0
|
|
368
|
-
else
|
|
369
|
-
print_warning "Homebrew installed but not yet in PATH. Restart your shell or run:"
|
|
370
|
-
echo " $brew_line"
|
|
371
|
-
return 1
|
|
372
|
-
fi
|
|
373
|
-
else
|
|
374
|
-
print_warning "Homebrew installation failed"
|
|
375
|
-
return 1
|
|
376
|
-
fi
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
# Fix Homebrew PATH for Apple Silicon and Intel Macs when brew is not in PATH.
|
|
380
|
-
# Modifies rc files only during interactive setup (not updates).
|
|
381
|
-
_check_req_fix_homebrew_path() {
|
|
382
|
-
# Apple Silicon Homebrew
|
|
383
|
-
if [[ -x "/opt/homebrew/bin/brew" ]] && [[ ":$PATH:" != *":/opt/homebrew/bin:"* ]]; then
|
|
384
|
-
eval "$(/opt/homebrew/bin/brew shellenv)"
|
|
385
|
-
print_warning "Homebrew not in PATH - added for this session"
|
|
386
|
-
|
|
387
|
-
# Only modify rc files during interactive setup (not updates)
|
|
388
|
-
# Users may intentionally remove these lines; re-adding on every update is harmful
|
|
389
|
-
if [[ "$NON_INTERACTIVE" != "true" ]]; then
|
|
390
|
-
# shellcheck disable=SC2016 # brew_line is written to rc files; must expand at shell startup, not now
|
|
391
|
-
local brew_line='eval "$(/opt/homebrew/bin/brew shellenv)"'
|
|
392
|
-
local fixed_rc=false
|
|
393
|
-
local rc_file
|
|
394
|
-
while IFS= read -r rc_file; do
|
|
395
|
-
[[ -z "$rc_file" ]] && continue
|
|
396
|
-
if ! grep -q '/opt/homebrew/bin/brew' "$rc_file" 2>/dev/null; then
|
|
397
|
-
{
|
|
398
|
-
echo ""
|
|
399
|
-
echo "# Homebrew (added by aidevops setup)"
|
|
400
|
-
echo "$brew_line"
|
|
401
|
-
} >>"$rc_file"
|
|
402
|
-
print_success "Added Homebrew to PATH in $rc_file"
|
|
403
|
-
fixed_rc=true
|
|
404
|
-
fi
|
|
405
|
-
done < <(get_all_shell_rcs)
|
|
406
|
-
|
|
407
|
-
if [[ "$fixed_rc" == "false" ]]; then
|
|
408
|
-
echo ""
|
|
409
|
-
echo " To fix permanently, add to your shell rc file:"
|
|
410
|
-
echo " $brew_line"
|
|
411
|
-
echo ""
|
|
412
|
-
fi
|
|
413
|
-
fi
|
|
414
|
-
fi
|
|
415
|
-
|
|
416
|
-
# Also check Intel Mac Homebrew location
|
|
417
|
-
# Skip entirely on Apple Silicon (ARM brew exists) — Intel brew shellenv prepends
|
|
418
|
-
# /usr/local/bin to PATH, causing x86 binaries to shadow ARM ones (GH#1510)
|
|
419
|
-
if [[ -x "/usr/local/bin/brew" ]] && [[ ":$PATH:" != *":/usr/local/bin:"* ]]; then
|
|
420
|
-
# On Apple Silicon with dual brew, do NOT add Intel brew to PATH — it breaks ARM brew
|
|
421
|
-
if [[ -x "/opt/homebrew/bin/brew" ]]; then
|
|
422
|
-
print_info "Intel Homebrew found but skipped (Apple Silicon uses /opt/homebrew)"
|
|
423
|
-
else
|
|
424
|
-
eval "$(/usr/local/bin/brew shellenv)"
|
|
425
|
-
print_warning "Homebrew (/usr/local/bin) not in PATH - added for this session"
|
|
426
|
-
|
|
427
|
-
# Only modify rc files during interactive setup (not updates)
|
|
428
|
-
if [[ "$NON_INTERACTIVE" != "true" ]]; then
|
|
429
|
-
# shellcheck disable=SC2016 # intel_brew_line is written to rc files; must expand at shell startup, not now
|
|
430
|
-
local intel_brew_line='eval "$(/usr/local/bin/brew shellenv)"'
|
|
431
|
-
local intel_fixed_rc=false
|
|
432
|
-
local intel_rc
|
|
433
|
-
while IFS= read -r intel_rc; do
|
|
434
|
-
[[ -z "$intel_rc" ]] && continue
|
|
435
|
-
if ! grep -q '/usr/local/bin/brew' "$intel_rc" 2>/dev/null; then
|
|
436
|
-
{
|
|
437
|
-
echo ""
|
|
438
|
-
echo "# Homebrew Intel Mac (added by aidevops setup)"
|
|
439
|
-
echo "$intel_brew_line"
|
|
440
|
-
} >>"$intel_rc"
|
|
441
|
-
print_success "Added Homebrew to PATH in $intel_rc"
|
|
442
|
-
intel_fixed_rc=true
|
|
443
|
-
fi
|
|
444
|
-
done < <(get_all_shell_rcs)
|
|
445
|
-
|
|
446
|
-
if [[ "$intel_fixed_rc" == "false" ]]; then
|
|
447
|
-
echo ""
|
|
448
|
-
echo " To fix permanently, add to your shell rc file:"
|
|
449
|
-
echo " $intel_brew_line"
|
|
450
|
-
echo ""
|
|
451
|
-
fi
|
|
452
|
-
fi
|
|
453
|
-
fi
|
|
454
|
-
fi
|
|
455
|
-
return 0
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
# Check system requirements
|
|
459
|
-
check_requirements() {
|
|
460
|
-
print_info "Checking system requirements..."
|
|
461
|
-
|
|
462
|
-
# Ensure Homebrew is in PATH (macOS Apple Silicon and Intel)
|
|
463
|
-
_check_req_fix_homebrew_path
|
|
464
|
-
|
|
465
|
-
local missing_deps=()
|
|
466
|
-
local missing_packages=()
|
|
467
|
-
|
|
468
|
-
# Detect package manager once for both package-name resolution and installation
|
|
469
|
-
local pkg_manager
|
|
470
|
-
pkg_manager=$(detect_package_manager)
|
|
471
|
-
|
|
472
|
-
# Check for required commands
|
|
473
|
-
# Format: command-name package-name (same when identical)
|
|
474
|
-
if ! command -v jq >/dev/null 2>&1; then
|
|
475
|
-
missing_deps+=("jq")
|
|
476
|
-
missing_packages+=("jq")
|
|
477
|
-
fi
|
|
478
|
-
if ! command -v curl >/dev/null 2>&1; then
|
|
479
|
-
missing_deps+=("curl")
|
|
480
|
-
missing_packages+=("curl")
|
|
481
|
-
fi
|
|
482
|
-
if ! command -v rg >/dev/null 2>&1; then
|
|
483
|
-
missing_deps+=("rg")
|
|
484
|
-
missing_packages+=("ripgrep")
|
|
485
|
-
fi
|
|
486
|
-
if ! command -v sqlite3 >/dev/null 2>&1; then
|
|
487
|
-
missing_deps+=("sqlite3")
|
|
488
|
-
# Package name varies: sqlite3 on Debian/Ubuntu (apt), sqlite on Homebrew/Fedora/Arch/Alpine
|
|
489
|
-
case "$pkg_manager" in
|
|
490
|
-
apt) missing_packages+=("sqlite3") ;;
|
|
491
|
-
*) missing_packages+=("sqlite") ;;
|
|
492
|
-
esac
|
|
493
|
-
fi
|
|
494
|
-
|
|
495
|
-
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
|
496
|
-
print_warning "Missing required dependencies: ${missing_deps[*]}"
|
|
497
|
-
|
|
498
|
-
if [[ "$pkg_manager" == "unknown" ]]; then
|
|
499
|
-
print_error "Could not detect package manager"
|
|
500
|
-
echo ""
|
|
501
|
-
echo "Please install manually:"
|
|
502
|
-
echo " macOS: brew install ${missing_packages[*]}"
|
|
503
|
-
echo " Ubuntu/Debian: sudo apt-get install ${missing_packages[*]}"
|
|
504
|
-
echo " Fedora: sudo dnf install ${missing_packages[*]}"
|
|
505
|
-
echo " CentOS/RHEL: sudo yum install ${missing_packages[*]}"
|
|
506
|
-
echo " Arch: sudo pacman -S ${missing_packages[*]}"
|
|
507
|
-
echo " Alpine: sudo apk add ${missing_packages[*]}"
|
|
508
|
-
exit 1
|
|
509
|
-
fi
|
|
510
|
-
|
|
511
|
-
# In non-interactive mode, fail fast on missing deps
|
|
512
|
-
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
513
|
-
print_error "Cannot continue without required dependencies (non-interactive mode)"
|
|
514
|
-
exit 1
|
|
515
|
-
fi
|
|
516
|
-
|
|
517
|
-
echo ""
|
|
518
|
-
local install_deps="Y"
|
|
519
|
-
setup_prompt install_deps "Install missing dependencies using $pkg_manager? [Y/n]: " "Y"
|
|
520
|
-
|
|
521
|
-
if [[ "$install_deps" =~ ^[Yy]?$ ]]; then
|
|
522
|
-
print_info "Installing ${missing_packages[*]}..."
|
|
523
|
-
if install_packages "$pkg_manager" "${missing_packages[@]}"; then
|
|
524
|
-
print_success "Dependencies installed successfully"
|
|
525
|
-
else
|
|
526
|
-
print_error "Failed to install dependencies"
|
|
527
|
-
exit 1
|
|
528
|
-
fi
|
|
529
|
-
else
|
|
530
|
-
print_error "Cannot continue without required dependencies"
|
|
531
|
-
exit 1
|
|
532
|
-
fi
|
|
533
|
-
fi
|
|
534
|
-
|
|
535
|
-
print_success "All required dependencies found"
|
|
536
|
-
return 0
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
# Check for quality/linting tools (shellcheck, shfmt, markdownlint)
|
|
540
|
-
# These are optional but recommended for development
|
|
541
|
-
_check_quality_tool() {
|
|
542
|
-
local tool_name="$1"
|
|
543
|
-
local version=""
|
|
544
|
-
|
|
545
|
-
if command -v "$tool_name" >/dev/null 2>&1; then
|
|
546
|
-
case "$tool_name" in
|
|
547
|
-
shellcheck)
|
|
548
|
-
version=$(shellcheck --version 2>/dev/null | head -1 || true)
|
|
549
|
-
;;
|
|
550
|
-
shfmt)
|
|
551
|
-
version=$(shfmt --version 2>/dev/null)
|
|
552
|
-
;;
|
|
553
|
-
esac
|
|
554
|
-
print_success "$tool_name: ${version:-installed}"
|
|
555
|
-
else
|
|
556
|
-
missing_tools+=("$tool_name")
|
|
557
|
-
fi
|
|
558
|
-
|
|
559
|
-
return 0
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
_check_markdownlint_tool() {
|
|
563
|
-
local version=""
|
|
564
|
-
|
|
565
|
-
if command -v markdownlint >/dev/null 2>&1; then
|
|
566
|
-
version=$(markdownlint --version 2>/dev/null | head -1 || true)
|
|
567
|
-
print_success "markdownlint: ${version:-installed}"
|
|
568
|
-
return 0
|
|
569
|
-
fi
|
|
570
|
-
|
|
571
|
-
if command -v markdownlint-cli2 >/dev/null 2>&1; then
|
|
572
|
-
version=$(markdownlint-cli2 --version 2>/dev/null | head -1 || true)
|
|
573
|
-
print_success "markdownlint-cli2: ${version:-installed}"
|
|
574
|
-
return 0
|
|
575
|
-
fi
|
|
576
|
-
|
|
577
|
-
missing_npm_tools+=("markdownlint-cli2")
|
|
578
|
-
return 0
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
_report_missing_quality_tools() {
|
|
582
|
-
if [[ ${#missing_tools[@]} -gt 0 ]]; then
|
|
583
|
-
print_warning "Missing quality tools: ${missing_tools[*]}"
|
|
584
|
-
fi
|
|
585
|
-
|
|
586
|
-
if [[ ${#missing_npm_tools[@]} -gt 0 ]]; then
|
|
587
|
-
print_warning "Missing npm quality tools: ${missing_npm_tools[*]}"
|
|
588
|
-
fi
|
|
589
|
-
|
|
590
|
-
print_info "These tools are used by linters-local.sh for code quality checks"
|
|
591
|
-
return 0
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
_install_missing_quality_tools() {
|
|
595
|
-
local pkg_manager="$1"
|
|
596
|
-
local install_quality="Y"
|
|
597
|
-
|
|
598
|
-
if [[ "$pkg_manager" == "unknown" ]]; then
|
|
599
|
-
print_info "Install manually:"
|
|
600
|
-
echo " macOS: brew install ${missing_tools[*]}"
|
|
601
|
-
echo " Ubuntu/Debian: sudo apt-get install ${missing_tools[*]}"
|
|
602
|
-
echo " Fedora: sudo dnf install ${missing_tools[*]}"
|
|
603
|
-
return 0
|
|
604
|
-
fi
|
|
605
|
-
|
|
606
|
-
echo ""
|
|
607
|
-
setup_prompt install_quality "Install quality tools using $pkg_manager? [Y/n]: " "Y"
|
|
608
|
-
|
|
609
|
-
if [[ "$install_quality" =~ ^[Yy]?$ ]]; then
|
|
610
|
-
print_info "Installing ${missing_tools[*]}..."
|
|
611
|
-
if install_packages "$pkg_manager" "${missing_tools[@]}"; then
|
|
612
|
-
print_success "Quality tools installed successfully"
|
|
613
|
-
else
|
|
614
|
-
print_warning "Failed to install some quality tools - continuing anyway"
|
|
615
|
-
fi
|
|
616
|
-
else
|
|
617
|
-
print_info "Skipped quality tools installation"
|
|
618
|
-
print_info "Install later: $pkg_manager install ${missing_tools[*]}"
|
|
619
|
-
fi
|
|
620
|
-
|
|
621
|
-
return 0
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
_install_missing_npm_quality_tools() {
|
|
625
|
-
local install_npm_quality="Y"
|
|
626
|
-
|
|
627
|
-
if ! command -v npm >/dev/null 2>&1; then
|
|
628
|
-
print_warning "npm not found; cannot auto-install ${missing_npm_tools[*]}"
|
|
629
|
-
print_info "Install Node.js/npm, then run: npm install -g ${missing_npm_tools[*]}"
|
|
630
|
-
return 0
|
|
631
|
-
fi
|
|
632
|
-
|
|
633
|
-
echo ""
|
|
634
|
-
setup_prompt install_npm_quality "Install npm quality tools (npm install -g ${missing_npm_tools[*]})? [Y/n]: " "Y"
|
|
635
|
-
if [[ "$install_npm_quality" =~ ^[Yy]?$ ]]; then
|
|
636
|
-
print_info "Installing npm quality tools: ${missing_npm_tools[*]}..."
|
|
637
|
-
if npm install -g "${missing_npm_tools[@]}" >/dev/null 2>&1; then
|
|
638
|
-
print_success "npm quality tools installed successfully"
|
|
639
|
-
else
|
|
640
|
-
print_warning "Failed to install npm quality tools - continuing anyway"
|
|
641
|
-
fi
|
|
642
|
-
else
|
|
643
|
-
print_info "Skipped npm quality tools installation"
|
|
644
|
-
print_info "Install later: npm install -g ${missing_npm_tools[*]}"
|
|
645
|
-
fi
|
|
646
|
-
|
|
647
|
-
return 0
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
check_quality_tools() {
|
|
651
|
-
print_info "Checking quality tools..."
|
|
652
|
-
|
|
653
|
-
local missing_tools=()
|
|
654
|
-
local missing_npm_tools=()
|
|
655
|
-
|
|
656
|
-
_check_quality_tool "shellcheck"
|
|
657
|
-
_check_quality_tool "shfmt"
|
|
658
|
-
_check_markdownlint_tool
|
|
659
|
-
|
|
660
|
-
if [[ ${#missing_tools[@]} -eq 0 && ${#missing_npm_tools[@]} -eq 0 ]]; then
|
|
661
|
-
print_success "All quality tools installed"
|
|
662
|
-
return 0
|
|
663
|
-
fi
|
|
664
|
-
|
|
665
|
-
_report_missing_quality_tools
|
|
666
|
-
|
|
667
|
-
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
668
|
-
if [[ ${#missing_tools[@]} -gt 0 ]]; then
|
|
669
|
-
print_info "Install later: brew install ${missing_tools[*]}"
|
|
670
|
-
fi
|
|
671
|
-
if [[ ${#missing_npm_tools[@]} -gt 0 ]]; then
|
|
672
|
-
if command -v npm >/dev/null 2>&1; then
|
|
673
|
-
print_info "Install later: npm install -g ${missing_npm_tools[*]}"
|
|
674
|
-
else
|
|
675
|
-
print_info "Install later: install npm, then run npm install -g ${missing_npm_tools[*]}"
|
|
676
|
-
fi
|
|
677
|
-
fi
|
|
678
|
-
return 0
|
|
679
|
-
fi
|
|
680
|
-
|
|
681
|
-
# Offer to install
|
|
682
|
-
local pkg_manager
|
|
683
|
-
pkg_manager=$(detect_package_manager)
|
|
684
|
-
|
|
685
|
-
if [[ ${#missing_tools[@]} -gt 0 ]]; then
|
|
686
|
-
_install_missing_quality_tools "$pkg_manager"
|
|
687
|
-
fi
|
|
688
|
-
|
|
689
|
-
if [[ ${#missing_npm_tools[@]} -gt 0 ]]; then
|
|
690
|
-
_install_missing_npm_quality_tools
|
|
691
|
-
fi
|
|
692
|
-
|
|
693
|
-
return 0
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
verify_location() {
|
|
697
|
-
local current_dir
|
|
698
|
-
current_dir="$(pwd)"
|
|
699
|
-
local expected_location="$HOME/Git/aidevops"
|
|
700
|
-
|
|
701
|
-
if [[ "$current_dir" != "$expected_location" ]]; then
|
|
702
|
-
print_warning "Repository is not in the recommended location"
|
|
703
|
-
print_info "Current location: $current_dir"
|
|
704
|
-
print_info "Recommended location: $expected_location"
|
|
705
|
-
echo ""
|
|
706
|
-
echo "For optimal AI assistant integration, consider moving this repository to:"
|
|
707
|
-
echo " mkdir -p ~/git"
|
|
708
|
-
echo " mv '$current_dir' '$expected_location'"
|
|
709
|
-
echo ""
|
|
710
|
-
else
|
|
711
|
-
print_success "Repository is in the recommended location: $expected_location"
|
|
712
|
-
fi
|
|
713
|
-
return 0
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
set_permissions() {
|
|
717
|
-
print_info "Setting proper file permissions..."
|
|
718
|
-
|
|
719
|
-
local deployed_dir="$HOME/.aidevops/agents"
|
|
720
|
-
|
|
721
|
-
# Set permissions on DEPLOYED agents (not the git repo, to avoid dirtying the working tree)
|
|
722
|
-
# See: https://github.com/marcusquinn/aidevops/issues/2286
|
|
723
|
-
if [[ -d "$deployed_dir/scripts" ]]; then
|
|
724
|
-
chmod +x "$deployed_dir/scripts/"*.sh 2>/dev/null || true
|
|
725
|
-
# Also handle modularised subdirectories (e.g. memory/, supervisor-modules/)
|
|
726
|
-
find "$deployed_dir/scripts" -mindepth 2 -name "*.sh" -exec chmod +x {} + 2>/dev/null || true
|
|
727
|
-
fi
|
|
728
|
-
|
|
729
|
-
# Secure configuration files (these are in the user's config dir, not the repo)
|
|
730
|
-
chmod 600 "$HOME/.config/aidevops/"*.json 2>/dev/null || true
|
|
731
|
-
# Also secure repo-local configs if present (for interactive setup from repo root)
|
|
732
|
-
chmod 600 configs/*.json 2>/dev/null || true
|
|
733
|
-
|
|
734
|
-
print_success "File permissions set"
|
|
735
|
-
return 0
|
|
736
|
-
}
|