aidevops 3.0.12 → 3.1.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/VERSION +1 -1
- package/aidevops.sh +4 -2
- package/package.json +1 -1
- package/setup-modules/mcp-setup.sh +64 -65
- package/setup-modules/migrations.sh +101 -0
- package/setup-modules/plugins.sh +21 -11
- package/setup-modules/shell-env.sh +38 -9
- package/setup-modules/tool-install.sh +101 -19
- package/setup.sh +26 -32
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.1.1
|
package/aidevops.sh
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# AI DevOps Framework CLI
|
|
4
4
|
# Usage: aidevops <command> [options]
|
|
5
5
|
#
|
|
6
|
-
# Version: 3.
|
|
6
|
+
# Version: 3.1.1
|
|
7
7
|
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
|
|
@@ -105,7 +105,9 @@ check_file() {
|
|
|
105
105
|
# Ensure file ends with a trailing newline (prevents malformed appends)
|
|
106
106
|
ensure_trailing_newline() {
|
|
107
107
|
local file="$1"
|
|
108
|
-
|
|
108
|
+
local last
|
|
109
|
+
last="$(tail -c 1 "$file"; printf x)"
|
|
110
|
+
[[ -s "$file" ]] && [[ "$last" != $'\n'x ]] && printf '\n' >>"$file"
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
# Initialize repos.json if it doesn't exist
|
package/package.json
CHANGED
|
@@ -10,6 +10,13 @@ trap 'rc=$?; echo "[ERROR] ${BASH_SOURCE[0]}:${LINENO} exit $rc" >&2' ERR
|
|
|
10
10
|
shopt -s inherit_errexit 2>/dev/null || true
|
|
11
11
|
|
|
12
12
|
install_mcp_packages() {
|
|
13
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
14
|
+
if ! command -v bun &>/dev/null && ! command -v npm &>/dev/null; then
|
|
15
|
+
print_skip "MCP packages" "neither bun nor npm found" "Install bun: brew install oven-sh/bun/bun (or npm via Node.js)"
|
|
16
|
+
setup_track_deferred "MCP packages" "Install bun or npm"
|
|
17
|
+
return 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
13
20
|
print_info "Installing MCP server packages globally (eliminates npx startup delay)..."
|
|
14
21
|
|
|
15
22
|
# Security note: MCP servers run as persistent processes with access to conversation
|
|
@@ -27,12 +34,6 @@ install_mcp_packages() {
|
|
|
27
34
|
"@steipete/claude-code-mcp"
|
|
28
35
|
)
|
|
29
36
|
|
|
30
|
-
if ! command -v bun &>/dev/null && ! command -v npm &>/dev/null; then
|
|
31
|
-
print_warning "Neither bun nor npm found - cannot install MCP packages"
|
|
32
|
-
print_info "Install bun (recommended): npm install -g bun OR brew install oven-sh/bun/bun"
|
|
33
|
-
return 0
|
|
34
|
-
fi
|
|
35
|
-
|
|
36
37
|
local installer="npm"
|
|
37
38
|
command -v bun &>/dev/null && installer="bun"
|
|
38
39
|
print_info "Using $installer to install/update Node.js MCP packages..."
|
|
@@ -205,36 +206,33 @@ update_mcp_paths_in_opencode() {
|
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
setup_localwp_mcp() {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
# Check if LocalWP is installed
|
|
209
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
211
210
|
local localwp_found=false
|
|
212
211
|
if [[ -d "/Applications/Local.app" ]] || [[ -d "$HOME/Applications/Local.app" ]]; then
|
|
213
212
|
localwp_found=true
|
|
214
213
|
fi
|
|
215
214
|
|
|
216
215
|
if [[ "$localwp_found" != "true" ]]; then
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
print_skip "LocalWP MCP" "LocalWP not installed" "Install from https://localwp.com/ then re-run setup"
|
|
217
|
+
setup_track_skipped "LocalWP MCP" "LocalWP not installed"
|
|
219
218
|
return 0
|
|
220
219
|
fi
|
|
221
220
|
|
|
222
|
-
print_success "LocalWP found"
|
|
223
|
-
|
|
224
|
-
# Check if npm is available
|
|
225
221
|
if ! command -v npm &>/dev/null; then
|
|
226
|
-
|
|
227
|
-
|
|
222
|
+
print_skip "LocalWP MCP" "npm not found" "Install Node.js and npm first"
|
|
223
|
+
setup_track_deferred "LocalWP MCP" "Install Node.js/npm, then re-run setup"
|
|
228
224
|
return 0
|
|
229
225
|
fi
|
|
230
226
|
|
|
231
|
-
#
|
|
227
|
+
# Prerequisites met — proceed with setup
|
|
228
|
+
print_info "Setting up LocalWP MCP server..."
|
|
229
|
+
|
|
232
230
|
if command -v mcp-local-wp &>/dev/null; then
|
|
233
231
|
print_success "LocalWP MCP server already installed"
|
|
232
|
+
setup_track_configured "LocalWP MCP"
|
|
234
233
|
return 0
|
|
235
234
|
fi
|
|
236
235
|
|
|
237
|
-
# Offer to install mcp-local-wp
|
|
238
236
|
print_info "LocalWP MCP server enables AI assistants to query WordPress databases"
|
|
239
237
|
read -r -p "Install LocalWP MCP server (@verygoodplugins/mcp-local-wp)? [Y/n]: " install_mcp
|
|
240
238
|
|
|
@@ -242,6 +240,7 @@ setup_localwp_mcp() {
|
|
|
242
240
|
if run_with_spinner "Installing LocalWP MCP server" npm_global_install "@verygoodplugins/mcp-local-wp"; then
|
|
243
241
|
print_info "Start with: ~/.aidevops/agents/scripts/localhost-helper.sh start-mcp"
|
|
244
242
|
print_info "Or configure in OpenCode MCP settings for auto-start"
|
|
243
|
+
setup_track_configured "LocalWP MCP"
|
|
245
244
|
else
|
|
246
245
|
print_info "Try manually: sudo npm install -g @verygoodplugins/mcp-local-wp"
|
|
247
246
|
fi
|
|
@@ -254,48 +253,47 @@ setup_localwp_mcp() {
|
|
|
254
253
|
}
|
|
255
254
|
|
|
256
255
|
setup_augment_context_engine() {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
# Check Node.js version (requires 22+)
|
|
256
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
260
257
|
if ! command -v node &>/dev/null; then
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
return
|
|
258
|
+
print_skip "Augment Context Engine" "Node.js not installed" "Install Node.js 22+: brew install node@22 (macOS) or nvm install 22"
|
|
259
|
+
setup_track_deferred "Augment Context Engine" "Install Node.js 22+"
|
|
260
|
+
return 0
|
|
264
261
|
fi
|
|
265
262
|
|
|
266
263
|
local node_version
|
|
267
264
|
node_version=$(node --version 2>/dev/null | cut -d'v' -f2 | cut -d'.' -f1)
|
|
268
265
|
if [[ -z "$node_version" ]] || ! [[ "$node_version" =~ ^[0-9]+$ ]]; then
|
|
269
|
-
|
|
270
|
-
|
|
266
|
+
print_skip "Augment Context Engine" "could not determine Node.js version"
|
|
267
|
+
setup_track_skipped "Augment Context Engine" "Node.js version unknown"
|
|
268
|
+
return 0
|
|
271
269
|
fi
|
|
272
270
|
if [[ "$node_version" -lt 22 ]]; then
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return
|
|
271
|
+
print_skip "Augment Context Engine" "requires Node.js 22+, found v$node_version" "Upgrade: brew install node@22 (macOS) or nvm install 22"
|
|
272
|
+
setup_track_deferred "Augment Context Engine" "Upgrade Node.js to 22+ (currently v$node_version)"
|
|
273
|
+
return 0
|
|
276
274
|
fi
|
|
277
275
|
|
|
278
|
-
# Check if auggie is installed
|
|
279
276
|
if ! command -v auggie &>/dev/null; then
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
return
|
|
277
|
+
print_skip "Augment Context Engine" "Auggie CLI not installed" "Install: npm install -g @augmentcode/auggie@prerelease && auggie login"
|
|
278
|
+
setup_track_deferred "Augment Context Engine" "Install Auggie CLI: npm install -g @augmentcode/auggie@prerelease"
|
|
279
|
+
return 0
|
|
284
280
|
fi
|
|
285
281
|
|
|
286
|
-
# Check if logged in
|
|
287
282
|
if [[ ! -f "$HOME/.augment/session.json" ]]; then
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
return
|
|
283
|
+
print_skip "Augment Context Engine" "Auggie not logged in" "Run: auggie login"
|
|
284
|
+
setup_track_deferred "Augment Context Engine" "Run: auggie login"
|
|
285
|
+
return 0
|
|
291
286
|
fi
|
|
292
287
|
|
|
288
|
+
# Prerequisites met — proceed with setup
|
|
289
|
+
print_info "Setting up Augment Context Engine MCP..."
|
|
293
290
|
print_success "Auggie CLI found and authenticated"
|
|
294
291
|
|
|
295
292
|
# MCP configuration is handled by generate-opencode-agents.sh for OpenCode
|
|
296
293
|
|
|
297
294
|
print_info "Augment Context Engine available as MCP in OpenCode"
|
|
298
295
|
print_info "Verification: 'What is this project? Please use codebase retrieval tool.'"
|
|
296
|
+
setup_track_configured "Augment Context Engine"
|
|
299
297
|
|
|
300
298
|
return 0
|
|
301
299
|
}
|
|
@@ -479,34 +477,35 @@ add_opencode_plugin() {
|
|
|
479
477
|
}
|
|
480
478
|
|
|
481
479
|
setup_opencode_plugins() {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
# Check if OpenCode is installed
|
|
480
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
485
481
|
if ! command -v opencode &>/dev/null; then
|
|
486
|
-
|
|
487
|
-
|
|
482
|
+
print_skip "OpenCode plugins" "OpenCode not installed" "Install from https://opencode.ai"
|
|
483
|
+
setup_track_skipped "OpenCode plugins" "OpenCode not installed"
|
|
488
484
|
return 0
|
|
489
485
|
fi
|
|
490
486
|
|
|
491
|
-
# Check if config exists
|
|
492
487
|
local opencode_config
|
|
493
488
|
if ! opencode_config=$(find_opencode_config); then
|
|
494
|
-
|
|
489
|
+
print_skip "OpenCode plugins" "OpenCode config not found" "Run 'opencode' once to create config, then re-run setup"
|
|
490
|
+
setup_track_deferred "OpenCode plugins" "Run 'opencode' once to create config"
|
|
495
491
|
return 0
|
|
496
492
|
fi
|
|
497
493
|
|
|
498
|
-
# Check if jq is available
|
|
499
494
|
if ! command -v jq &>/dev/null; then
|
|
500
|
-
|
|
495
|
+
print_skip "OpenCode plugins" "jq not installed" "Install jq: brew install jq (macOS) or apt install jq"
|
|
496
|
+
setup_track_deferred "OpenCode plugins" "Install jq"
|
|
501
497
|
return 0
|
|
502
498
|
fi
|
|
503
499
|
|
|
500
|
+
# Prerequisites met — proceed with setup
|
|
501
|
+
print_info "Setting up OpenCode plugins..."
|
|
502
|
+
|
|
504
503
|
# Setup aidevops compaction plugin (local file plugin)
|
|
505
504
|
local aidevops_plugin_path="$HOME/.aidevops/agents/plugins/opencode-aidevops/index.mjs"
|
|
506
505
|
if [[ -f "$aidevops_plugin_path" ]]; then
|
|
507
|
-
print_info "Setting up aidevops compaction plugin..."
|
|
508
506
|
add_opencode_plugin "file://$HOME/.aidevops" "file://${aidevops_plugin_path}" "$opencode_config"
|
|
509
507
|
print_success "aidevops compaction plugin registered (preserves context across compaction)"
|
|
508
|
+
setup_track_configured "OpenCode plugins"
|
|
510
509
|
fi
|
|
511
510
|
|
|
512
511
|
# Note: opencode-anthropic-auth is built into OpenCode v1.1.36+
|
|
@@ -514,7 +513,7 @@ setup_opencode_plugins() {
|
|
|
514
513
|
# Removed in v2.90.0 - see PR #230.
|
|
515
514
|
|
|
516
515
|
print_info "After setup, authenticate with: opencode auth login"
|
|
517
|
-
print_info "
|
|
516
|
+
print_info " - For Claude OAuth: Select 'Anthropic' -> 'Claude Pro/Max' (built-in)"
|
|
518
517
|
|
|
519
518
|
return 0
|
|
520
519
|
}
|
|
@@ -566,32 +565,31 @@ setup_seo_mcps() {
|
|
|
566
565
|
}
|
|
567
566
|
|
|
568
567
|
setup_google_analytics_mcp() {
|
|
569
|
-
print_info "Setting up Google Analytics MCP..."
|
|
570
|
-
|
|
571
568
|
local gsc_creds="$HOME/.config/aidevops/gsc-credentials.json"
|
|
572
569
|
|
|
573
|
-
# Check
|
|
570
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
574
571
|
local opencode_config
|
|
575
572
|
if ! opencode_config=$(find_opencode_config); then
|
|
576
|
-
|
|
573
|
+
print_skip "Google Analytics MCP" "OpenCode config not found" "Run 'opencode' once to create config, then re-run setup"
|
|
574
|
+
setup_track_skipped "Google Analytics MCP" "OpenCode config not found"
|
|
577
575
|
return 0
|
|
578
576
|
fi
|
|
579
577
|
|
|
580
|
-
# Check if jq is available
|
|
581
578
|
if ! command -v jq &>/dev/null; then
|
|
582
|
-
|
|
583
|
-
|
|
579
|
+
print_skip "Google Analytics MCP" "jq not installed" "Install jq: brew install jq (macOS) or apt install jq"
|
|
580
|
+
setup_track_deferred "Google Analytics MCP" "Install jq"
|
|
584
581
|
return 0
|
|
585
582
|
fi
|
|
586
583
|
|
|
587
|
-
# Check if pipx is available
|
|
588
584
|
if ! command -v pipx &>/dev/null; then
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
print_info "Then re-run setup to add Google Analytics MCP"
|
|
585
|
+
print_skip "Google Analytics MCP" "pipx not installed" "Install pipx: brew install pipx (macOS) or pip install pipx"
|
|
586
|
+
setup_track_deferred "Google Analytics MCP" "Install pipx"
|
|
592
587
|
return 0
|
|
593
588
|
fi
|
|
594
589
|
|
|
590
|
+
# Prerequisites met — proceed with setup
|
|
591
|
+
print_info "Setting up Google Analytics MCP..."
|
|
592
|
+
|
|
595
593
|
# Auto-detect credentials from shared GSC service account
|
|
596
594
|
local creds_path=""
|
|
597
595
|
local project_id=""
|
|
@@ -672,19 +670,20 @@ setup_google_analytics_mcp() {
|
|
|
672
670
|
}
|
|
673
671
|
|
|
674
672
|
setup_quickfile_mcp() {
|
|
675
|
-
print_info "Setting up QuickFile MCP server..."
|
|
676
|
-
|
|
677
673
|
local quickfile_dir="$HOME/Git/quickfile-mcp"
|
|
678
674
|
local credentials_dir="$HOME/.config/.quickfile-mcp"
|
|
679
675
|
local credentials_file="$credentials_dir/credentials.json"
|
|
680
676
|
|
|
681
|
-
# Check
|
|
677
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
682
678
|
if ! command -v node &>/dev/null; then
|
|
683
|
-
|
|
684
|
-
|
|
679
|
+
print_skip "QuickFile MCP" "Node.js not installed" "Install Node.js 18+: brew install node (macOS) or nvm install 18"
|
|
680
|
+
setup_track_deferred "QuickFile MCP" "Install Node.js 18+"
|
|
685
681
|
return 0
|
|
686
682
|
fi
|
|
687
683
|
|
|
684
|
+
# Prerequisites met — proceed with setup
|
|
685
|
+
print_info "Setting up QuickFile MCP server..."
|
|
686
|
+
|
|
688
687
|
# Check if already cloned and built
|
|
689
688
|
if [[ -f "$quickfile_dir/dist/index.js" ]]; then
|
|
690
689
|
print_success "QuickFile MCP already installed at $quickfile_dir"
|
|
@@ -37,6 +37,22 @@ cleanup_deprecated_paths() {
|
|
|
37
37
|
"$agents_dir/youtube"
|
|
38
38
|
# osgrep removed — disproportionate CPU/disk cost vs rg + LLM comprehension
|
|
39
39
|
"$agents_dir/tools/context/osgrep.md"
|
|
40
|
+
# GH#5155: scripts archived upstream but orphaned in deployed installs
|
|
41
|
+
# (rsync only adds/overwrites, doesn't delete removed files)
|
|
42
|
+
"$agents_dir/scripts/pattern-tracker-helper.sh"
|
|
43
|
+
"$agents_dir/scripts/quality-sweep-helper.sh"
|
|
44
|
+
"$agents_dir/scripts/quality-loop-helper.sh"
|
|
45
|
+
"$agents_dir/scripts/review-pulse-helper.sh"
|
|
46
|
+
"$agents_dir/scripts/self-improve-helper.sh"
|
|
47
|
+
"$agents_dir/scripts/coderabbit-pulse-helper.sh"
|
|
48
|
+
"$agents_dir/scripts/coderabbit-task-creator-helper.sh"
|
|
49
|
+
"$agents_dir/scripts/audit-task-creator-helper.sh"
|
|
50
|
+
"$agents_dir/scripts/batch-cleanup-helper.sh"
|
|
51
|
+
"$agents_dir/scripts/coordinator-helper.sh"
|
|
52
|
+
"$agents_dir/scripts/finding-to-task-helper.sh"
|
|
53
|
+
"$agents_dir/scripts/objective-runner-helper.sh"
|
|
54
|
+
"$agents_dir/scripts/ralph-loop-helper.sh"
|
|
55
|
+
"$agents_dir/scripts/stale-pr-helper.sh"
|
|
40
56
|
)
|
|
41
57
|
|
|
42
58
|
for path in "${deprecated_paths[@]}"; do
|
|
@@ -963,3 +979,88 @@ migrate_pulse_repos_to_repos_json() {
|
|
|
963
979
|
|
|
964
980
|
return 0
|
|
965
981
|
}
|
|
982
|
+
|
|
983
|
+
# Migrate orphaned supervisor-helper.sh and supervisor/ modules (GH#5147)
|
|
984
|
+
# After the supervisor-to-pulse-wrapper migration (PR #2291, PR #2475), the
|
|
985
|
+
# upstream repo moved supervisor files to supervisor-archived/. But aidevops
|
|
986
|
+
# update (rsync) only adds/overwrites — it doesn't delete files that no longer
|
|
987
|
+
# exist in the source. Users who installed before the migration retain:
|
|
988
|
+
# - ~/.aidevops/agents/scripts/supervisor-helper.sh (old entry point)
|
|
989
|
+
# - ~/.aidevops/agents/scripts/supervisor/ (old module directory)
|
|
990
|
+
# - cron/launchd entries invoking supervisor-helper.sh pulse
|
|
991
|
+
# These orphaned files shadow the new pulse-wrapper.sh architecture.
|
|
992
|
+
# This migration removes the orphaned files and rewrites scheduler entries.
|
|
993
|
+
migrate_orphaned_supervisor() {
|
|
994
|
+
local agents_dir="$HOME/.aidevops/agents"
|
|
995
|
+
local scripts_dir="$agents_dir/scripts"
|
|
996
|
+
local cleaned=0
|
|
997
|
+
|
|
998
|
+
# 1. Remove orphaned supervisor-helper.sh from deployed scripts
|
|
999
|
+
# The canonical location is now supervisor-archived/supervisor-helper.sh
|
|
1000
|
+
# (shipped for reference/tests only, not as an active entry point)
|
|
1001
|
+
if [[ -f "$scripts_dir/supervisor-helper.sh" ]]; then
|
|
1002
|
+
rm -f "$scripts_dir/supervisor-helper.sh"
|
|
1003
|
+
print_info "Removed orphaned supervisor-helper.sh from deployed scripts"
|
|
1004
|
+
((++cleaned))
|
|
1005
|
+
fi
|
|
1006
|
+
|
|
1007
|
+
# 2. Remove orphaned supervisor/ module directory
|
|
1008
|
+
# The canonical location is now supervisor-archived/ (shipped by rsync)
|
|
1009
|
+
# Only remove if it's the old modules dir (contains pulse.sh, dispatch.sh, etc.)
|
|
1010
|
+
# Do NOT remove supervisor-archived/ — that's the intentional archive
|
|
1011
|
+
if [[ -d "$scripts_dir/supervisor" && ! -L "$scripts_dir/supervisor" ]]; then
|
|
1012
|
+
# Verify it's the old module directory (not something user-created)
|
|
1013
|
+
if [[ -f "$scripts_dir/supervisor/pulse.sh" ]] ||
|
|
1014
|
+
[[ -f "$scripts_dir/supervisor/dispatch.sh" ]] ||
|
|
1015
|
+
[[ -f "$scripts_dir/supervisor/_common.sh" ]]; then
|
|
1016
|
+
rm -rf "$scripts_dir/supervisor"
|
|
1017
|
+
print_info "Removed orphaned supervisor/ module directory from deployed scripts"
|
|
1018
|
+
((++cleaned))
|
|
1019
|
+
fi
|
|
1020
|
+
fi
|
|
1021
|
+
|
|
1022
|
+
# 3. Migrate cron entries from supervisor-helper.sh to pulse-wrapper.sh
|
|
1023
|
+
# Old pattern: */2 * * * * ... supervisor-helper.sh pulse ...
|
|
1024
|
+
# New pattern: already installed by setup.sh's pulse section
|
|
1025
|
+
# Strategy: remove old entries; setup.sh will install the new one if pulse is enabled
|
|
1026
|
+
local current_crontab
|
|
1027
|
+
current_crontab=$(crontab -l 2>/dev/null) || current_crontab=""
|
|
1028
|
+
if echo "$current_crontab" | grep -qF "supervisor-helper.sh"; then
|
|
1029
|
+
# Remove all cron lines referencing supervisor-helper.sh
|
|
1030
|
+
local new_crontab
|
|
1031
|
+
new_crontab=$(echo "$current_crontab" | grep -v "supervisor-helper.sh")
|
|
1032
|
+
if [[ -n "$new_crontab" ]]; then
|
|
1033
|
+
printf '%s\n' "$new_crontab" | crontab - || true
|
|
1034
|
+
else
|
|
1035
|
+
# All entries were supervisor-helper.sh — remove crontab entirely
|
|
1036
|
+
crontab -r || true
|
|
1037
|
+
fi
|
|
1038
|
+
print_info "Removed orphaned supervisor-helper.sh cron entries"
|
|
1039
|
+
print_info " pulse-wrapper.sh will be installed by setup.sh if supervisor pulse is enabled"
|
|
1040
|
+
((++cleaned))
|
|
1041
|
+
fi
|
|
1042
|
+
|
|
1043
|
+
# 4. Migrate launchd entries from old supervisor label (macOS only)
|
|
1044
|
+
# Old label: com.aidevops.supervisor-pulse (from cron.sh/launchd.sh)
|
|
1045
|
+
# New label: com.aidevops.aidevops-supervisor-pulse (from setup.sh)
|
|
1046
|
+
# setup.sh already handles the new label cleanup at line ~1000, but
|
|
1047
|
+
# the old label from cron.sh may also be present
|
|
1048
|
+
if [[ "$(uname -s)" == "Darwin" ]]; then
|
|
1049
|
+
local old_label="com.aidevops.supervisor-pulse"
|
|
1050
|
+
local old_plist="$HOME/Library/LaunchAgents/${old_label}.plist"
|
|
1051
|
+
if _launchd_has_agent "$old_label" || [[ -f "$old_plist" ]]; then
|
|
1052
|
+
# Use launchctl remove by label — works even when the plist file is
|
|
1053
|
+
# missing (orphaned agent loaded without a backing file on disk)
|
|
1054
|
+
launchctl remove "$old_label" || true
|
|
1055
|
+
rm -f "$old_plist"
|
|
1056
|
+
print_info "Removed orphaned supervisor-pulse LaunchAgent ($old_label)"
|
|
1057
|
+
((++cleaned))
|
|
1058
|
+
fi
|
|
1059
|
+
fi
|
|
1060
|
+
|
|
1061
|
+
if [[ $cleaned -gt 0 ]]; then
|
|
1062
|
+
print_success "Cleaned up $cleaned orphaned supervisor artifact(s) — pulse-wrapper.sh is the active system"
|
|
1063
|
+
fi
|
|
1064
|
+
|
|
1065
|
+
return 0
|
|
1066
|
+
}
|
package/setup-modules/plugins.sh
CHANGED
|
@@ -117,12 +117,13 @@ deploy_plugins() {
|
|
|
117
117
|
local target_dir="$1"
|
|
118
118
|
local plugins_file="$2"
|
|
119
119
|
|
|
120
|
-
# Skip if no plugins.json or no jq
|
|
120
|
+
# Skip if no plugins.json or no jq (GH#5240: clear skip messages)
|
|
121
121
|
if [[ ! -f "$plugins_file" ]]; then
|
|
122
122
|
return 0
|
|
123
123
|
fi
|
|
124
124
|
if ! command -v jq &>/dev/null; then
|
|
125
|
-
|
|
125
|
+
print_skip "Plugin deployment" "jq not installed" "Install jq: brew install jq (macOS) or apt install jq"
|
|
126
|
+
setup_track_deferred "Plugin deployment" "Install jq"
|
|
126
127
|
return 0
|
|
127
128
|
fi
|
|
128
129
|
|
|
@@ -401,15 +402,18 @@ check_skill_updates() {
|
|
|
401
402
|
}
|
|
402
403
|
|
|
403
404
|
scan_imported_skills() {
|
|
404
|
-
|
|
405
|
-
|
|
405
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
406
406
|
local security_helper="$HOME/.aidevops/agents/scripts/security-helper.sh"
|
|
407
407
|
|
|
408
408
|
if [[ ! -f "$security_helper" ]]; then
|
|
409
|
-
|
|
409
|
+
print_skip "Skill security scan" "security-helper.sh not found" "Deploy agents first (setup.sh), then re-run"
|
|
410
|
+
setup_track_skipped "Skill security scan" "security-helper.sh not found"
|
|
410
411
|
return 0
|
|
411
412
|
fi
|
|
412
413
|
|
|
414
|
+
# Prerequisites met — proceed with setup
|
|
415
|
+
print_info "Running security scan on imported skills..."
|
|
416
|
+
|
|
413
417
|
# Install skill-scanner if not present
|
|
414
418
|
# Pre-check: cisco-ai-skill-scanner requires Python >= 3.10
|
|
415
419
|
# Fallback chain: uv -> pipx -> venv+symlink -> pip3 --user (legacy)
|
|
@@ -484,8 +488,7 @@ scan_imported_skills() {
|
|
|
484
488
|
}
|
|
485
489
|
|
|
486
490
|
setup_multi_tenant_credentials() {
|
|
487
|
-
|
|
488
|
-
|
|
491
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
489
492
|
local credential_helper="$HOME/.aidevops/agents/scripts/credential-helper.sh"
|
|
490
493
|
|
|
491
494
|
if [[ ! -f "$credential_helper" ]]; then
|
|
@@ -494,10 +497,14 @@ setup_multi_tenant_credentials() {
|
|
|
494
497
|
fi
|
|
495
498
|
|
|
496
499
|
if [[ ! -f "$credential_helper" ]]; then
|
|
497
|
-
|
|
500
|
+
print_skip "Multi-tenant credentials" "credential-helper.sh not found" "Deploy agents first (setup.sh), then re-run"
|
|
501
|
+
setup_track_skipped "Multi-tenant credentials" "credential-helper.sh not found"
|
|
498
502
|
return 0
|
|
499
503
|
fi
|
|
500
504
|
|
|
505
|
+
# Prerequisites met — proceed with setup
|
|
506
|
+
print_info "Multi-tenant credential storage..."
|
|
507
|
+
|
|
501
508
|
# Check if already initialized
|
|
502
509
|
if [[ -d "$HOME/.config/aidevops/tenants" ]]; then
|
|
503
510
|
local tenant_count
|
|
@@ -547,8 +554,7 @@ setup_multi_tenant_credentials() {
|
|
|
547
554
|
}
|
|
548
555
|
|
|
549
556
|
check_tool_updates() {
|
|
550
|
-
|
|
551
|
-
|
|
557
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
552
558
|
local tool_check_script="$HOME/.aidevops/agents/scripts/tool-version-check.sh"
|
|
553
559
|
|
|
554
560
|
if [[ ! -f "$tool_check_script" ]]; then
|
|
@@ -557,10 +563,14 @@ check_tool_updates() {
|
|
|
557
563
|
fi
|
|
558
564
|
|
|
559
565
|
if [[ ! -f "$tool_check_script" ]]; then
|
|
560
|
-
|
|
566
|
+
print_skip "Tool updates" "version check script not found" "Deploy agents first (setup.sh), then re-run"
|
|
567
|
+
setup_track_skipped "Tool updates" "version check script not found"
|
|
561
568
|
return 0
|
|
562
569
|
fi
|
|
563
570
|
|
|
571
|
+
# Prerequisites met — proceed with setup
|
|
572
|
+
print_info "Checking for tool updates..."
|
|
573
|
+
|
|
564
574
|
# Run the check in quiet mode first to see if there are updates
|
|
565
575
|
# Capture both output and exit code
|
|
566
576
|
local outdated_output
|
|
@@ -94,24 +94,25 @@ get_all_shell_rcs() {
|
|
|
94
94
|
|
|
95
95
|
# Offer to install Oh My Zsh if zsh is the default shell and OMZ is not present
|
|
96
96
|
setup_oh_my_zsh() {
|
|
97
|
-
#
|
|
97
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
98
98
|
if ! command -v zsh >/dev/null 2>&1; then
|
|
99
|
-
|
|
99
|
+
print_skip "Oh My Zsh" "zsh not installed" "Install zsh first, then re-run setup"
|
|
100
|
+
setup_track_skipped "Oh My Zsh" "zsh not installed"
|
|
100
101
|
return 0
|
|
101
102
|
fi
|
|
102
103
|
|
|
103
|
-
# Check if Oh My Zsh is already installed
|
|
104
104
|
if [[ -d "$HOME/.oh-my-zsh" ]]; then
|
|
105
105
|
print_success "Oh My Zsh already installed"
|
|
106
|
+
setup_track_configured "Oh My Zsh"
|
|
106
107
|
return 0
|
|
107
108
|
fi
|
|
108
109
|
|
|
109
110
|
local default_shell
|
|
110
111
|
default_shell=$(detect_default_shell)
|
|
111
112
|
|
|
112
|
-
# Only offer if zsh is the default shell (or on macOS where it's the system default)
|
|
113
113
|
if [[ "$default_shell" != "zsh" && "$(uname)" != "Darwin" ]]; then
|
|
114
|
-
|
|
114
|
+
print_skip "Oh My Zsh" "default shell is $default_shell (not zsh)" "Change default shell to zsh: chsh -s \$(which zsh)"
|
|
115
|
+
setup_track_skipped "Oh My Zsh" "default shell is $default_shell"
|
|
115
116
|
return 0
|
|
116
117
|
fi
|
|
117
118
|
|
|
@@ -386,6 +387,10 @@ check_optional_deps() {
|
|
|
386
387
|
print_info "Checking optional dependencies..."
|
|
387
388
|
|
|
388
389
|
local missing_optional=()
|
|
390
|
+
local recommended_python_formula
|
|
391
|
+
recommended_python_formula=$(get_recommended_python_formula)
|
|
392
|
+
local python_required_major="${PYTHON_REQUIRED_MAJOR:-3}"
|
|
393
|
+
local python_required_minor="${PYTHON_REQUIRED_MINOR:-10}"
|
|
389
394
|
|
|
390
395
|
if ! command -v sshpass >/dev/null 2>&1; then
|
|
391
396
|
missing_optional+=("sshpass")
|
|
@@ -393,6 +398,26 @@ check_optional_deps() {
|
|
|
393
398
|
print_success "sshpass found"
|
|
394
399
|
fi
|
|
395
400
|
|
|
401
|
+
local python3_bin=""
|
|
402
|
+
if python3_bin=$(find_python3); then
|
|
403
|
+
local python_version
|
|
404
|
+
python_version=$("$python3_bin" -c 'import sys; print("{}.{}.{}".format(sys.version_info[0], sys.version_info[1], sys.version_info[2]))' 2>/dev/null || true)
|
|
405
|
+
local python_major
|
|
406
|
+
python_major=$(echo "$python_version" | cut -d. -f1)
|
|
407
|
+
local python_minor
|
|
408
|
+
python_minor=$(echo "$python_version" | cut -d. -f2)
|
|
409
|
+
|
|
410
|
+
if [[ "$python_major" =~ ^[0-9]+$ ]] && [[ "$python_minor" =~ ^[0-9]+$ ]] && { ((python_major > python_required_major)) || { ((python_major == python_required_major)) && ((python_minor >= python_required_minor)); }; }; then
|
|
411
|
+
print_success "Python $python_version found ($python_required_major.$python_required_minor+ required)"
|
|
412
|
+
else
|
|
413
|
+
print_warning "Python $python_version found, but $python_required_major.$python_required_minor+ is recommended for all skills/tools"
|
|
414
|
+
offer_python_brew_install "upgrade" "$recommended_python_formula" || true
|
|
415
|
+
fi
|
|
416
|
+
else
|
|
417
|
+
print_warning "Python 3 not found"
|
|
418
|
+
offer_python_brew_install "install" "$recommended_python_formula" || true
|
|
419
|
+
fi
|
|
420
|
+
|
|
396
421
|
if [[ ${#missing_optional[@]} -gt 0 ]]; then
|
|
397
422
|
print_warning "Missing optional dependencies: ${missing_optional[*]}"
|
|
398
423
|
echo " sshpass - needed for password-based SSH (like Hostinger)"
|
|
@@ -822,12 +847,12 @@ ALIASES
|
|
|
822
847
|
|
|
823
848
|
# Install terminal title integration that syncs tab titles with git repo/branch
|
|
824
849
|
setup_terminal_title() {
|
|
825
|
-
|
|
826
|
-
|
|
850
|
+
# Check prerequisites before announcing setup (GH#5240)
|
|
827
851
|
local setup_script=".agents/scripts/terminal-title-setup.sh"
|
|
828
852
|
|
|
829
853
|
if [[ ! -f "$setup_script" ]]; then
|
|
830
|
-
|
|
854
|
+
print_skip "Terminal title" "setup script not found" "Deploy agents first (setup.sh), then re-run"
|
|
855
|
+
setup_track_skipped "Terminal title" "setup script not found"
|
|
831
856
|
return 0
|
|
832
857
|
fi
|
|
833
858
|
|
|
@@ -843,10 +868,14 @@ setup_terminal_title() {
|
|
|
843
868
|
done < <(get_all_shell_rcs)
|
|
844
869
|
|
|
845
870
|
if [[ "$title_configured" == "true" ]]; then
|
|
846
|
-
|
|
871
|
+
print_success "Terminal title integration already configured"
|
|
872
|
+
setup_track_configured "Terminal title"
|
|
847
873
|
return 0
|
|
848
874
|
fi
|
|
849
875
|
|
|
876
|
+
# Prerequisites met — proceed with setup
|
|
877
|
+
print_info "Setting up terminal title integration..."
|
|
878
|
+
|
|
850
879
|
# Show current status before asking
|
|
851
880
|
echo ""
|
|
852
881
|
print_info "Terminal title integration syncs your terminal tab with git repo/branch"
|
|
@@ -57,7 +57,7 @@ setup_git_clis() {
|
|
|
57
57
|
echo "📋 Next steps - authenticate each CLI:"
|
|
58
58
|
for pkg in "${missing_packages[@]}"; do
|
|
59
59
|
case "$pkg" in
|
|
60
|
-
gh) echo " • gh auth login" ;;
|
|
60
|
+
gh) echo " • gh auth login -s workflow (workflow scope required for CI PRs)" ;;
|
|
61
61
|
glab) echo " • glab auth login" ;;
|
|
62
62
|
esac
|
|
63
63
|
done
|
|
@@ -1001,6 +1001,92 @@ setup_ssh_key() {
|
|
|
1001
1001
|
return 0
|
|
1002
1002
|
}
|
|
1003
1003
|
|
|
1004
|
+
# Check installed Python version against latest stable available from package manager.
|
|
1005
|
+
# Warns if an upgrade is available but never auto-upgrades (GH#5237).
|
|
1006
|
+
# Works on macOS (Homebrew) and Linux (apt/dnf).
|
|
1007
|
+
check_python_version() {
|
|
1008
|
+
print_info "Checking Python version..."
|
|
1009
|
+
|
|
1010
|
+
# 1. Check currently installed Python
|
|
1011
|
+
local python3_bin
|
|
1012
|
+
if ! python3_bin=$(find_python3); then
|
|
1013
|
+
print_warning "Python 3 not found"
|
|
1014
|
+
echo ""
|
|
1015
|
+
echo " Install options:"
|
|
1016
|
+
if [[ "$PLATFORM_MACOS" == "true" ]]; then
|
|
1017
|
+
echo " brew install python3"
|
|
1018
|
+
elif command -v apt-get >/dev/null 2>&1; then
|
|
1019
|
+
echo " sudo apt install python3"
|
|
1020
|
+
elif command -v dnf >/dev/null 2>&1; then
|
|
1021
|
+
echo " sudo dnf install python3"
|
|
1022
|
+
else
|
|
1023
|
+
echo " Install Python 3 via your system package manager"
|
|
1024
|
+
fi
|
|
1025
|
+
echo ""
|
|
1026
|
+
return 0
|
|
1027
|
+
fi
|
|
1028
|
+
|
|
1029
|
+
local installed_version
|
|
1030
|
+
installed_version=$("$python3_bin" --version 2>&1 | cut -d' ' -f2)
|
|
1031
|
+
local installed_major installed_minor
|
|
1032
|
+
installed_major=$(echo "$installed_version" | cut -d. -f1)
|
|
1033
|
+
installed_minor=$(echo "$installed_version" | cut -d. -f2)
|
|
1034
|
+
|
|
1035
|
+
# 2. Determine latest stable version from package manager
|
|
1036
|
+
local latest_version=""
|
|
1037
|
+
|
|
1038
|
+
if [[ "$PLATFORM_MACOS" == "true" ]] && command -v brew >/dev/null 2>&1; then
|
|
1039
|
+
# Homebrew: `brew info python3` outputs "python@3.X: 3.X.Y" on the first line
|
|
1040
|
+
latest_version=$(brew info --json=v2 python3 2>/dev/null |
|
|
1041
|
+
python3 -c "import sys,json; d=json.load(sys.stdin); print(d['formulae'][0]['versions']['stable'])" 2>/dev/null) || latest_version=""
|
|
1042
|
+
elif command -v apt-cache >/dev/null 2>&1; then
|
|
1043
|
+
# Debian/Ubuntu: get candidate version from apt-cache
|
|
1044
|
+
latest_version=$(apt-cache policy python3 2>/dev/null |
|
|
1045
|
+
awk '/Candidate:/{print $2}' |
|
|
1046
|
+
grep -oE '[0-9]+\.[0-9]+\.[0-9]+') || latest_version=""
|
|
1047
|
+
elif command -v dnf >/dev/null 2>&1; then
|
|
1048
|
+
# Fedora/RHEL: get available version from dnf
|
|
1049
|
+
latest_version=$(dnf info python3 2>/dev/null |
|
|
1050
|
+
awk '/^Version/{print $3}') || latest_version=""
|
|
1051
|
+
fi
|
|
1052
|
+
|
|
1053
|
+
# 3. Compare versions and advise
|
|
1054
|
+
if [[ -z "$latest_version" ]]; then
|
|
1055
|
+
# Could not determine latest — just report installed version
|
|
1056
|
+
print_success "Python $installed_version found"
|
|
1057
|
+
return 0
|
|
1058
|
+
fi
|
|
1059
|
+
|
|
1060
|
+
local latest_major latest_minor
|
|
1061
|
+
latest_major=$(echo "$latest_version" | cut -d. -f1)
|
|
1062
|
+
latest_minor=$(echo "$latest_version" | cut -d. -f2)
|
|
1063
|
+
|
|
1064
|
+
# Compare major.minor (patch differences are not worth warning about)
|
|
1065
|
+
if [[ "$installed_major" -lt "$latest_major" ]] ||
|
|
1066
|
+
{ [[ "$installed_major" -eq "$latest_major" ]] && [[ "$installed_minor" -lt "$latest_minor" ]]; }; then
|
|
1067
|
+
print_warning "Python $installed_version installed, but $latest_version is available"
|
|
1068
|
+
echo ""
|
|
1069
|
+
echo " Some tools and skills require Python 3.10+."
|
|
1070
|
+
echo " Upgrade is recommended but not required."
|
|
1071
|
+
echo ""
|
|
1072
|
+
if [[ "$PLATFORM_MACOS" == "true" ]]; then
|
|
1073
|
+
echo " Upgrade command:"
|
|
1074
|
+
echo " brew upgrade python3"
|
|
1075
|
+
elif command -v apt-get >/dev/null 2>&1; then
|
|
1076
|
+
echo " Upgrade command:"
|
|
1077
|
+
echo " sudo apt update && sudo apt install python3"
|
|
1078
|
+
elif command -v dnf >/dev/null 2>&1; then
|
|
1079
|
+
echo " Upgrade command:"
|
|
1080
|
+
echo " sudo dnf upgrade python3"
|
|
1081
|
+
fi
|
|
1082
|
+
echo ""
|
|
1083
|
+
else
|
|
1084
|
+
print_success "Python $installed_version found (latest stable: $latest_version)"
|
|
1085
|
+
fi
|
|
1086
|
+
|
|
1087
|
+
return 0
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1004
1090
|
setup_python_env() {
|
|
1005
1091
|
print_info "Setting up Python environment for DSPy..."
|
|
1006
1092
|
|
|
@@ -1370,36 +1456,32 @@ setup_ai_orchestration() {
|
|
|
1370
1456
|
print_info "Setting up AI orchestration frameworks..."
|
|
1371
1457
|
|
|
1372
1458
|
local has_python=false
|
|
1373
|
-
|
|
1374
|
-
|
|
1459
|
+
local python_required_major="${PYTHON_REQUIRED_MAJOR:-3}"
|
|
1460
|
+
local python_required_minor="${PYTHON_REQUIRED_MINOR:-10}"
|
|
1461
|
+
local recommended_python_formula
|
|
1462
|
+
recommended_python_formula=$(get_recommended_python_formula)
|
|
1463
|
+
|
|
1464
|
+
# Check Python (prefer Homebrew/pyenv over system) — uses shared helpers
|
|
1465
|
+
# from _common.sh (get_recommended_python_formula, find_python3,
|
|
1466
|
+
# offer_python_brew_install) to avoid duplicating version-check logic.
|
|
1375
1467
|
local python3_bin
|
|
1376
1468
|
if python3_bin=$(find_python3); then
|
|
1377
1469
|
local python_version
|
|
1378
|
-
python_version=$("$python3_bin"
|
|
1470
|
+
python_version=$("$python3_bin" -c 'import sys; print("{}.{}.{}".format(sys.version_info[0], sys.version_info[1], sys.version_info[2]))' 2>/dev/null || true)
|
|
1379
1471
|
local major minor
|
|
1380
1472
|
major=$(echo "$python_version" | cut -d. -f1)
|
|
1381
1473
|
minor=$(echo "$python_version" | cut -d. -f2)
|
|
1382
1474
|
|
|
1383
|
-
if [[ $major -
|
|
1475
|
+
if [[ "$major" =~ ^[0-9]+$ ]] && [[ "$minor" =~ ^[0-9]+$ ]] && { ((major > python_required_major)) || { ((major == python_required_major)) && ((minor >= python_required_minor)); }; }; then
|
|
1384
1476
|
has_python=true
|
|
1385
|
-
print_success "Python $python_version found (
|
|
1477
|
+
print_success "Python $python_version found ($python_required_major.$python_required_minor+ required)"
|
|
1386
1478
|
else
|
|
1387
|
-
print_warning "Python
|
|
1388
|
-
|
|
1389
|
-
echo " Upgrade options:"
|
|
1390
|
-
echo " macOS (Homebrew): brew install python@3.12"
|
|
1391
|
-
echo " macOS (pyenv): pyenv install 3.12 && pyenv global 3.12"
|
|
1392
|
-
echo " Ubuntu/Debian: sudo apt install python3.12"
|
|
1393
|
-
echo " Fedora: sudo dnf install python3.12"
|
|
1394
|
-
echo ""
|
|
1479
|
+
print_warning "Python $python_required_major.$python_required_minor+ required for AI orchestration, found $python_version"
|
|
1480
|
+
offer_python_brew_install "upgrade" "$recommended_python_formula" || true
|
|
1395
1481
|
fi
|
|
1396
1482
|
else
|
|
1397
1483
|
print_warning "Python 3 not found - AI orchestration frameworks unavailable"
|
|
1398
|
-
|
|
1399
|
-
echo " Install options:"
|
|
1400
|
-
echo " macOS: brew install python@3.12"
|
|
1401
|
-
echo " Linux: sudo apt install python3 (or dnf/pacman)"
|
|
1402
|
-
echo ""
|
|
1484
|
+
offer_python_brew_install "install" "$recommended_python_formula" || true
|
|
1403
1485
|
return 0
|
|
1404
1486
|
fi
|
|
1405
1487
|
|
package/setup.sh
CHANGED
|
@@ -10,7 +10,7 @@ shopt -s inherit_errexit 2>/dev/null || true
|
|
|
10
10
|
# AI Assistant Server Access Framework Setup Script
|
|
11
11
|
# Helps developers set up the framework for their infrastructure
|
|
12
12
|
#
|
|
13
|
-
# Version: 3.
|
|
13
|
+
# Version: 3.1.1
|
|
14
14
|
#
|
|
15
15
|
# Quick Install:
|
|
16
16
|
# npm install -g aidevops && aidevops update (recommended)
|
|
@@ -22,6 +22,7 @@ GREEN='\033[0;32m'
|
|
|
22
22
|
BLUE='\033[0;34m'
|
|
23
23
|
YELLOW='\033[1;33m'
|
|
24
24
|
RED='\033[0;31m'
|
|
25
|
+
GRAY='\033[0;90m'
|
|
25
26
|
NC='\033[0m' # No Color
|
|
26
27
|
|
|
27
28
|
# Global flags
|
|
@@ -29,6 +30,11 @@ CLEAN_MODE=false
|
|
|
29
30
|
INTERACTIVE_MODE=false
|
|
30
31
|
NON_INTERACTIVE="${AIDEVOPS_NON_INTERACTIVE:-false}"
|
|
31
32
|
UPDATE_TOOLS_MODE=false
|
|
33
|
+
# Python compatibility floor used by setup checks and skill/tool gating.
|
|
34
|
+
# Keep in sync with setup-modules/plugins.sh requirements.
|
|
35
|
+
PYTHON_REQUIRED_MAJOR=3
|
|
36
|
+
PYTHON_REQUIRED_MINOR=10
|
|
37
|
+
export PYTHON_REQUIRED_MAJOR PYTHON_REQUIRED_MINOR
|
|
32
38
|
# Platform constants — exported for sourced setup-modules (shell-env.sh,
|
|
33
39
|
# tool-install.sh) that reference them at runtime.
|
|
34
40
|
PLATFORM_MACOS=$([[ "$(uname -s)" == "Darwin" ]] && echo true || echo false)
|
|
@@ -362,26 +368,8 @@ find_opencode_config() {
|
|
|
362
368
|
return 1
|
|
363
369
|
}
|
|
364
370
|
|
|
365
|
-
#
|
|
366
|
-
|
|
367
|
-
local candidates=(
|
|
368
|
-
"/opt/homebrew/bin/python3"
|
|
369
|
-
"/usr/local/bin/python3"
|
|
370
|
-
"$HOME/.pyenv/shims/python3"
|
|
371
|
-
)
|
|
372
|
-
for candidate in "${candidates[@]}"; do
|
|
373
|
-
if [[ -x "$candidate" ]]; then
|
|
374
|
-
echo "$candidate"
|
|
375
|
-
return 0
|
|
376
|
-
fi
|
|
377
|
-
done
|
|
378
|
-
# Fallback to PATH
|
|
379
|
-
if command -v python3 &>/dev/null; then
|
|
380
|
-
command -v python3
|
|
381
|
-
return 0
|
|
382
|
-
fi
|
|
383
|
-
return 1
|
|
384
|
-
}
|
|
371
|
+
# get_latest_homebrew_python_formula() and find_python3() are defined in
|
|
372
|
+
# _common.sh (sourced above). Not duplicated here — see GH#5239 review.
|
|
385
373
|
|
|
386
374
|
# Install a package globally via npm, with sudo when needed on Linux.
|
|
387
375
|
# Usage: npm_global_install "package-name" OR npm_global_install "package@version"
|
|
@@ -709,6 +697,7 @@ main() {
|
|
|
709
697
|
print_info "Non-interactive mode: deploying agents and running safe migrations only"
|
|
710
698
|
verify_location
|
|
711
699
|
check_requirements
|
|
700
|
+
check_python_version
|
|
712
701
|
set_permissions
|
|
713
702
|
migrate_old_backups
|
|
714
703
|
migrate_loop_state_directories
|
|
@@ -716,6 +705,7 @@ main() {
|
|
|
716
705
|
migrate_mcp_env_to_credentials
|
|
717
706
|
migrate_pulse_repos_to_repos_json
|
|
718
707
|
cleanup_deprecated_paths
|
|
708
|
+
migrate_orphaned_supervisor
|
|
719
709
|
cleanup_deprecated_mcps
|
|
720
710
|
cleanup_stale_bun_opencode
|
|
721
711
|
validate_opencode_config
|
|
@@ -772,6 +762,7 @@ main() {
|
|
|
772
762
|
|
|
773
763
|
# Optional steps with confirmation in interactive mode
|
|
774
764
|
confirm_step "Check optional dependencies (bun, node, python)" && check_optional_deps
|
|
765
|
+
confirm_step "Check Python version (recommend upgrade if outdated)" && check_python_version
|
|
775
766
|
confirm_step "Setup recommended tools (Tabby, Zed, etc.)" && setup_recommended_tools
|
|
776
767
|
confirm_step "Setup MiniSim (iOS/Android emulator launcher)" && setup_minisim
|
|
777
768
|
confirm_step "Setup Git CLIs (gh, glab, tea)" && setup_git_clis
|
|
@@ -795,6 +786,7 @@ main() {
|
|
|
795
786
|
confirm_step "Migrate mcp-env.sh -> credentials.sh" && migrate_mcp_env_to_credentials
|
|
796
787
|
confirm_step "Migrate pulse-repos.json into repos.json" && migrate_pulse_repos_to_repos_json
|
|
797
788
|
confirm_step "Cleanup deprecated agent paths" && cleanup_deprecated_paths
|
|
789
|
+
confirm_step "Migrate orphaned supervisor to pulse-wrapper" && migrate_orphaned_supervisor
|
|
798
790
|
confirm_step "Cleanup deprecated MCP entries (hetzner, serper, etc.)" && cleanup_deprecated_mcps
|
|
799
791
|
confirm_step "Cleanup stale bun opencode install" && cleanup_stale_bun_opencode
|
|
800
792
|
confirm_step "Validate and repair OpenCode config schema" && validate_opencode_config
|
|
@@ -833,8 +825,11 @@ main() {
|
|
|
833
825
|
confirm_step "Disable on-demand MCPs globally" && disable_ondemand_mcps
|
|
834
826
|
fi
|
|
835
827
|
|
|
828
|
+
# Print setup summary before final success message (GH#5240)
|
|
829
|
+
print_setup_summary
|
|
830
|
+
|
|
836
831
|
echo ""
|
|
837
|
-
print_success "
|
|
832
|
+
print_success "Setup complete!"
|
|
838
833
|
|
|
839
834
|
# Enable auto-update if not already enabled
|
|
840
835
|
# Check both launchd (macOS) and cron (Linux) for existing installation
|
|
@@ -892,10 +887,6 @@ main() {
|
|
|
892
887
|
# - Non-interactive: only installs if config explicitly says true
|
|
893
888
|
local wrapper_script="$HOME/.aidevops/agents/scripts/pulse-wrapper.sh"
|
|
894
889
|
local pulse_label="com.aidevops.aidevops-supervisor-pulse"
|
|
895
|
-
local _aidevops_dir _pulse_repo_dir
|
|
896
|
-
_aidevops_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
897
|
-
_pulse_repo_dir=$(_resolve_main_worktree_dir "$_aidevops_dir")
|
|
898
|
-
|
|
899
890
|
# Read explicit user consent from config.jsonc (not merged defaults).
|
|
900
891
|
# Empty = user never configured this; "true"/"false" = explicit choice.
|
|
901
892
|
local _pulse_user_config=""
|
|
@@ -1009,12 +1000,14 @@ main() {
|
|
|
1009
1000
|
|
|
1010
1001
|
# XML-escape paths for safe plist embedding (prevents injection
|
|
1011
1002
|
# if $HOME or paths contain &, <, > characters)
|
|
1012
|
-
local _xml_wrapper_script _xml_home _xml_opencode_bin
|
|
1003
|
+
local _xml_wrapper_script _xml_home _xml_opencode_bin _xml_pulse_dir _xml_path
|
|
1013
1004
|
local _headless_xml_env=""
|
|
1014
1005
|
_xml_wrapper_script=$(_xml_escape "$wrapper_script")
|
|
1015
1006
|
_xml_home=$(_xml_escape "$HOME")
|
|
1016
1007
|
_xml_opencode_bin=$(_xml_escape "$opencode_bin")
|
|
1017
|
-
|
|
1008
|
+
# Use neutral workspace path for PULSE_DIR so supervisor sessions
|
|
1009
|
+
# are not associated with any specific managed repo (GH#5136).
|
|
1010
|
+
_xml_pulse_dir=$(_xml_escape "${HOME}/.aidevops/.agent-workspace")
|
|
1018
1011
|
_xml_path=$(_xml_escape "$PATH")
|
|
1019
1012
|
if [[ -n "${AIDEVOPS_HEADLESS_MODELS:-}" ]]; then
|
|
1020
1013
|
local _xml_headless_models
|
|
@@ -1061,7 +1054,7 @@ main() {
|
|
|
1061
1054
|
<key>OPENCODE_BIN</key>
|
|
1062
1055
|
<string>${_xml_opencode_bin}</string>
|
|
1063
1056
|
<key>PULSE_DIR</key>
|
|
1064
|
-
<string>${
|
|
1057
|
+
<string>${_xml_pulse_dir}</string>
|
|
1065
1058
|
<key>PULSE_STALE_THRESHOLD</key>
|
|
1066
1059
|
<string>1800</string>
|
|
1067
1060
|
${_headless_xml_env}
|
|
@@ -1092,8 +1085,9 @@ PLIST
|
|
|
1092
1085
|
# PATH= here, it overrides the global line and breaks nvm/bun/cargo.
|
|
1093
1086
|
# OPENCODE_BIN removed — resolved from PATH at runtime via command -v.
|
|
1094
1087
|
# See #4099 and #4240 for history.
|
|
1095
|
-
local
|
|
1096
|
-
|
|
1088
|
+
local _cron_pulse_dir _cron_wrapper_script _cron_headless_env=""
|
|
1089
|
+
# Use neutral workspace path for PULSE_DIR (GH#5136)
|
|
1090
|
+
_cron_pulse_dir=$(_cron_escape "${HOME}/.aidevops/.agent-workspace")
|
|
1097
1091
|
_cron_wrapper_script=$(_cron_escape "$wrapper_script")
|
|
1098
1092
|
if [[ -n "${AIDEVOPS_HEADLESS_MODELS:-}" ]]; then
|
|
1099
1093
|
local _cron_headless_models
|
|
@@ -1107,7 +1101,7 @@ PLIST
|
|
|
1107
1101
|
fi
|
|
1108
1102
|
(
|
|
1109
1103
|
crontab -l 2>/dev/null | grep -v 'aidevops: supervisor-pulse'
|
|
1110
|
-
echo "*/2 * * * * PULSE_DIR=${
|
|
1104
|
+
echo "*/2 * * * * PULSE_DIR=${_cron_pulse_dir}${_cron_headless_env} /bin/bash ${_cron_wrapper_script} >> \"\$HOME/.aidevops/logs/pulse-wrapper.log\" 2>&1 # aidevops: supervisor-pulse"
|
|
1111
1105
|
) | crontab - || true
|
|
1112
1106
|
if crontab -l 2>/dev/null | grep -qF "aidevops: supervisor-pulse"; then
|
|
1113
1107
|
print_info "Supervisor pulse enabled (cron, every 2 min). Disable: crontab -e and remove the supervisor-pulse line"
|