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.
@@ -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
- }