aidevops 3.11.13 → 3.11.15
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 +53 -1
- package/package.json +1 -1
- package/setup-modules/post-setup.sh +22 -0
- package/setup-modules/schedulers.sh +13 -5
- package/setup.sh +15 -3
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.11.
|
|
1
|
+
3.11.15
|
package/aidevops.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# AI DevOps Framework CLI
|
|
6
6
|
# Usage: aidevops <command> [options]
|
|
7
7
|
#
|
|
8
|
-
# Version: 3.11.
|
|
8
|
+
# Version: 3.11.15
|
|
9
9
|
|
|
10
10
|
set -euo pipefail
|
|
11
11
|
|
|
@@ -639,6 +639,58 @@ cmd_update() {
|
|
|
639
639
|
_update_check_tools
|
|
640
640
|
_update_sweep_opencode_symlinks
|
|
641
641
|
|
|
642
|
+
# t2898: When invoked interactively (terminal stdin AND not from the
|
|
643
|
+
# auto-update daemon itself, which sets AIDEVOPS_AUTO_UPDATE=1 in its
|
|
644
|
+
# environment), verify the daemon is healthy and warn if not. The
|
|
645
|
+
# advisory file gets picked up by the next session greeting so the
|
|
646
|
+
# user sees the warning even if they miss this output.
|
|
647
|
+
#
|
|
648
|
+
# Skip in headless / CI runs (no stdin, no TTY) to avoid spurious
|
|
649
|
+
# warnings in setup.sh-driven flows that already do their own check.
|
|
650
|
+
if [[ -t 0 ]] && [[ -z "${AIDEVOPS_AUTO_UPDATE:-}" ]] && [[ "${NON_INTERACTIVE:-false}" != "true" ]]; then
|
|
651
|
+
_update_check_daemon_health
|
|
652
|
+
fi
|
|
653
|
+
|
|
654
|
+
return 0
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
# t2898: post-update daemon health verification (interactive only).
|
|
658
|
+
# Side effect: writes ~/.aidevops/advisories/daemon-disabled.advisory when
|
|
659
|
+
# the daemon is unhealthy so the session greeting surfaces the warning.
|
|
660
|
+
# Cleared (file removed) when the daemon recovers.
|
|
661
|
+
_update_check_daemon_health() {
|
|
662
|
+
local helper="$HOME/.aidevops/agents/scripts/auto-update-helper.sh"
|
|
663
|
+
[[ -x "$helper" ]] || return 0
|
|
664
|
+
local advisory_dir="$HOME/.aidevops/advisories"
|
|
665
|
+
local advisory_file="$advisory_dir/daemon-disabled.advisory"
|
|
666
|
+
|
|
667
|
+
local hc_rc=0
|
|
668
|
+
"$helper" health-check --quiet >/dev/null 2>&1 || hc_rc=$?
|
|
669
|
+
|
|
670
|
+
if [[ "$hc_rc" -eq 0 ]]; then
|
|
671
|
+
# Healthy — clear any stale advisory.
|
|
672
|
+
[[ -f "$advisory_file" ]] && rm -f "$advisory_file"
|
|
673
|
+
return 0
|
|
674
|
+
fi
|
|
675
|
+
|
|
676
|
+
# Unhealthy — warn on stderr and write advisory.
|
|
677
|
+
mkdir -p "$advisory_dir" 2>/dev/null || return 0
|
|
678
|
+
local fix_cmd="aidevops auto-update enable"
|
|
679
|
+
[[ "$hc_rc" -eq 1 ]] && fix_cmd="aidevops auto-update check"
|
|
680
|
+
cat >"$advisory_file" <<EOF
|
|
681
|
+
auto-update daemon is not running normally on this runner. Without it, this
|
|
682
|
+
runner falls behind the fleet and may dispatch workers that fail because of
|
|
683
|
+
bugs already fixed upstream. See cross-runner-coordination.md §4.4.
|
|
684
|
+
|
|
685
|
+
Diagnose: aidevops auto-update health-check
|
|
686
|
+
Fix: ${fix_cmd}
|
|
687
|
+
EOF
|
|
688
|
+
|
|
689
|
+
if [[ "$hc_rc" -eq 1 ]]; then
|
|
690
|
+
print_warning "Auto-update daemon is stalled. Fix: ${fix_cmd}"
|
|
691
|
+
else
|
|
692
|
+
print_warning "Auto-update daemon is not running. Fix: ${fix_cmd}"
|
|
693
|
+
fi
|
|
642
694
|
return 0
|
|
643
695
|
}
|
|
644
696
|
# Uninstall helpers (extracted for complexity reduction)
|
package/package.json
CHANGED
|
@@ -32,6 +32,28 @@ setup_auto_update() {
|
|
|
32
32
|
"aidevops-auto-update"; then
|
|
33
33
|
_auto_update_installed=true
|
|
34
34
|
fi
|
|
35
|
+
# t2898: ALWAYS run idempotent re-install + health-check after the
|
|
36
|
+
# detection above, so every release self-heals broken installs (daemon
|
|
37
|
+
# unloaded by an OS update, scrubbed by a cron cleanup, etc.). The
|
|
38
|
+
# detection helper already handled the "freshly install if missing"
|
|
39
|
+
# interactive prompt; this loop ensures that even when the detection
|
|
40
|
+
# said "yes installed" the daemon is actually loaded right now and
|
|
41
|
+
# running on schedule.
|
|
42
|
+
if [[ "$_auto_update_installed" == "true" ]]; then
|
|
43
|
+
# Idempotent: no-op when daemon already loaded; re-installs only on drift.
|
|
44
|
+
bash "$auto_update_script" enable --idempotent >/dev/null 2>&1 || true
|
|
45
|
+
# Verify it's actually healthy. Surface any degradation so the
|
|
46
|
+
# operator sees it on every release deploy.
|
|
47
|
+
local _hc_rc=0
|
|
48
|
+
bash "$auto_update_script" health-check --quiet >/dev/null 2>&1 || _hc_rc=$?
|
|
49
|
+
if [[ "$_hc_rc" -eq 0 ]]; then
|
|
50
|
+
:
|
|
51
|
+
elif [[ "$_hc_rc" -eq 1 ]]; then
|
|
52
|
+
print_warning "Auto-update daemon installed but stalled — run: aidevops auto-update check"
|
|
53
|
+
elif [[ "$_hc_rc" -eq 2 ]]; then
|
|
54
|
+
print_warning "Auto-update daemon not loaded — run: aidevops auto-update enable"
|
|
55
|
+
fi
|
|
56
|
+
fi
|
|
35
57
|
if [[ "$_auto_update_installed" == "false" ]]; then
|
|
36
58
|
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
37
59
|
# Non-interactive: enable silently
|
|
@@ -683,10 +683,16 @@ _install_pulse_launchd() {
|
|
|
683
683
|
local _pulse_installed="$4"
|
|
684
684
|
local pulse_plist="$HOME/Library/LaunchAgents/${pulse_label}.plist"
|
|
685
685
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
_generate_pulse_plist_content "$pulse_label" "$wrapper_script" "$opencode_bin"
|
|
686
|
+
# Capture plist content before touching the existing file.
|
|
687
|
+
# This avoids the "unload old, then write fails" window that leaves a 0-byte plist.
|
|
688
|
+
local pulse_plist_content
|
|
689
|
+
pulse_plist_content=$(_generate_pulse_plist_content "$pulse_label" "$wrapper_script" "$opencode_bin")
|
|
690
|
+
|
|
691
|
+
# Defensive: if generation produced empty content, refuse to touch the existing plist.
|
|
692
|
+
if [[ -z "$pulse_plist_content" ]]; then
|
|
693
|
+
print_warning "Pulse plist generation produced empty content — leaving existing plist untouched"
|
|
694
|
+
return 1
|
|
695
|
+
fi
|
|
690
696
|
|
|
691
697
|
# Resolve interval for the user-facing message (matches what the plist contains).
|
|
692
698
|
local _interval_sec _interval_label
|
|
@@ -697,8 +703,10 @@ _install_pulse_launchd() {
|
|
|
697
703
|
_interval_label="${_interval_sec}s"
|
|
698
704
|
fi
|
|
699
705
|
|
|
706
|
+
# _launchd_install_if_changed handles unload-before-replace only when content
|
|
707
|
+
# has changed, and writes atomically via tmp+rename (see setup.sh).
|
|
700
708
|
# shell-portability: ignore next — _install_pulse_launchd is macOS-only (launchd)
|
|
701
|
-
if
|
|
709
|
+
if _launchd_install_if_changed "$pulse_label" "$pulse_plist" "$pulse_plist_content"; then
|
|
702
710
|
if [[ "$_pulse_installed" == "true" ]]; then
|
|
703
711
|
print_info "Supervisor pulse updated (launchd config regenerated, every ${_interval_label})"
|
|
704
712
|
else
|
package/setup.sh
CHANGED
|
@@ -12,7 +12,7 @@ shopt -s inherit_errexit 2>/dev/null || true
|
|
|
12
12
|
# AI Assistant Server Access Framework Setup Script
|
|
13
13
|
# Helps developers set up the framework for their infrastructure
|
|
14
14
|
#
|
|
15
|
-
# Version: 3.11.
|
|
15
|
+
# Version: 3.11.15
|
|
16
16
|
#
|
|
17
17
|
# Quick Install:
|
|
18
18
|
# npm install -g aidevops && aidevops update (recommended)
|
|
@@ -241,8 +241,20 @@ _launchd_install_if_changed() {
|
|
|
241
241
|
fi
|
|
242
242
|
fi
|
|
243
243
|
|
|
244
|
-
#
|
|
245
|
-
printf
|
|
244
|
+
# Atomic write: build at sibling tmp path, then rename into place.
|
|
245
|
+
# If printf is killed mid-write, the destination is untouched.
|
|
246
|
+
local tmp_plist="${plist_path}.tmp.$$"
|
|
247
|
+
if ! printf '%s\n' "$new_content" >"$tmp_plist"; then
|
|
248
|
+
rm -f "$tmp_plist"
|
|
249
|
+
return 1
|
|
250
|
+
fi
|
|
251
|
+
# Defensive: refuse to install an empty file (should be guaranteed by the
|
|
252
|
+
# caller's content check, but guard here too).
|
|
253
|
+
if [[ ! -s "$tmp_plist" ]]; then
|
|
254
|
+
rm -f "$tmp_plist"
|
|
255
|
+
return 1
|
|
256
|
+
fi
|
|
257
|
+
mv -f "$tmp_plist" "$plist_path"
|
|
246
258
|
launchctl load "$plist_path" 2>/dev/null || return 1
|
|
247
259
|
return 0
|
|
248
260
|
}
|