aidevops 3.13.57 → 3.13.59

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 CHANGED
@@ -1 +1 @@
1
- 3.13.57
1
+ 3.13.59
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.13.57
8
+ # Version: 3.13.59
9
9
 
10
10
  set -euo pipefail
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aidevops",
3
- "version": "3.13.57",
3
+ "version": "3.13.59",
4
4
  "description": "AI DevOps Framework - AI-assisted development workflows, code quality, and deployment automation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -57,8 +57,13 @@ _restart_pulse_if_running() {
57
57
  fi
58
58
  fi
59
59
 
60
- # No auto-restart — start it manually
61
- local pulse_script="${HOME}/.aidevops/agents/scripts/pulse-wrapper.sh"
60
+ # No auto-restart — start it manually. Prefer the canonical repo source so a
61
+ # background launch never depends on a path inside ~/.aidevops/agents/scripts/
62
+ # that may be in the middle of a future deploy swap (must-not-be-wiped-during-deploy).
63
+ local pulse_script="${INSTALL_DIR:-.}/.agents/scripts/pulse-wrapper.sh"
64
+ if [[ ! -x "$pulse_script" ]]; then
65
+ pulse_script="${HOME}/.aidevops/agents/scripts/pulse-wrapper.sh"
66
+ fi
62
67
  if [[ -x "$pulse_script" ]]; then
63
68
  nohup "$pulse_script" >>"${HOME}/.aidevops/logs/pulse-wrapper.log" 2>&1 &
64
69
  print_success "Pulse started manually (PID $!)"
@@ -307,6 +312,76 @@ _set_script_permissions_and_report() {
307
312
  return 0
308
313
  }
309
314
 
315
+ # _count_deployed_agent_files target_dir
316
+ # Prints the number of files in the deployed agents tree. Non-numeric output is
317
+ # normalised to 0 so deploy verification never compares an empty string.
318
+ _count_deployed_agent_files() {
319
+ local target_dir="$1"
320
+ local file_count="0"
321
+ if [[ -d "$target_dir" ]]; then
322
+ file_count=$(find "$target_dir" -type f 2>/dev/null | wc -l | tr -d '[:space:]')
323
+ fi
324
+ [[ "$file_count" =~ ^[0-9]+$ ]] || file_count=0
325
+ printf '%s\n' "$file_count"
326
+ return 0
327
+ }
328
+
329
+ # _restore_latest_agents_backup target_dir
330
+ # Restores the newest agents backup after a failed deploy verification. Backups
331
+ # are created by create_backup_with_rotation as ~/.aidevops/agents-backups/<ts>/agents.
332
+ _restore_latest_agents_backup() {
333
+ local target_dir="$1"
334
+ local backup_base="$HOME/.aidevops/agents-backups"
335
+ local latest_backup=""
336
+
337
+ if [[ ! -d "$backup_base" ]]; then
338
+ print_warning "No agents backup directory found for restore: $backup_base"
339
+ return 1
340
+ fi
341
+
342
+ latest_backup=$(find "$backup_base" -maxdepth 2 -type d -name agents 2>/dev/null | sort | tail -n 1)
343
+ if [[ -z "$latest_backup" || ! -d "$latest_backup" ]]; then
344
+ print_warning "No restorable agents backup found under $backup_base"
345
+ return 1
346
+ fi
347
+
348
+ print_warning "Restoring agents from latest backup: $latest_backup"
349
+ rm -rf "$target_dir"
350
+ mkdir -p "$(dirname "$target_dir")"
351
+ if cp -a "$latest_backup" "$target_dir"; then
352
+ print_success "Restored agents directory from backup"
353
+ return 0
354
+ fi
355
+
356
+ print_error "Failed to restore agents directory from backup: $latest_backup"
357
+ return 1
358
+ }
359
+
360
+ # _verify_deployed_agents_tree target_dir
361
+ # Verifies the deployed agents tree is plausibly complete before .deployed-sha is
362
+ # written. This catches empty/partial deploys that would otherwise suppress the
363
+ # next auto-update retry by stamping the new SHA.
364
+ _verify_deployed_agents_tree() {
365
+ local target_dir="$1"
366
+ local min_files="${AIDEVOPS_AGENT_DEPLOY_MIN_FILES:-100}"
367
+ local file_count="0"
368
+
369
+ [[ "$min_files" =~ ^[0-9]+$ ]] || min_files=100
370
+
371
+ if [[ ! -d "$target_dir/scripts" ]]; then
372
+ print_error "Deploy verification failed: $target_dir/scripts missing after swap"
373
+ return 1
374
+ fi
375
+
376
+ file_count=$(_count_deployed_agent_files "$target_dir")
377
+ if [[ "$file_count" -lt "$min_files" ]]; then
378
+ print_error "Deploy verification failed: $target_dir has $file_count files (< $min_files)"
379
+ return 1
380
+ fi
381
+
382
+ return 0
383
+ }
384
+
310
385
  # _install_opencode_plugin_deps target_dir
311
386
  # Installs node_modules for the opencode-aidevops plugin.
312
387
  # GH#17829: @bufbuild/protobuf was missing; GH#17891: only symlink on first run.
@@ -651,12 +726,14 @@ deploy_aidevops_agents() {
651
726
  fi
652
727
 
653
728
  # Postcondition: verify the swap actually produced a functional agents dir.
654
- # _atomic_stage_and_deploy_agents returns 0 on success, but a belt-and-
655
- # suspenders check here catches any future regression where the function
656
- # might return early without correctly populating $target_dir (GH#22014).
657
- if [[ ! -d "$target_dir/scripts" ]]; then
658
- print_error "Deploy verification failed: $target_dir/scripts missing after swap"
729
+ # _atomic_stage_and_deploy_agents returns 0 on success, but this belt-and-
730
+ # suspenders check catches future regressions where the function returns early
731
+ # without correctly populating $target_dir (GH#22014/GH#21973). Do not write
732
+ # .deployed-sha unless this passes; otherwise auto-update would suppress the
733
+ # next retry even though agents/ is empty or partial.
734
+ if ! _verify_deployed_agents_tree "$target_dir"; then
659
735
  print_error "The agents directory was not correctly deployed — setup cannot continue"
736
+ _restore_latest_agents_backup "$target_dir" || true
660
737
  return 1
661
738
  fi
662
739
 
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.13.57
15
+ # Version: 3.13.59
16
16
  #
17
17
  # Quick Install:
18
18
  # npm install -g aidevops && aidevops update (recommended)
@@ -1144,6 +1144,30 @@ _setup_lock_pid_alive() {
1144
1144
  return $?
1145
1145
  }
1146
1146
 
1147
+ _setup_lock_dir_age_seconds() {
1148
+ local lock_dir="$1"
1149
+ local lock_mtime=""
1150
+ local now=""
1151
+ if ! [[ -d "$lock_dir" ]]; then
1152
+ printf '%s\n' 0
1153
+ return 0
1154
+ fi
1155
+ if type _file_mtime_epoch >/dev/null 2>&1; then
1156
+ lock_mtime=$(_file_mtime_epoch "$lock_dir" 2>/dev/null || true)
1157
+ elif [[ "$(uname -s 2>/dev/null || true)" == "Darwin" || "$(uname -s 2>/dev/null || true)" == "FreeBSD" ]]; then
1158
+ lock_mtime=$(stat -f %m "$lock_dir" 2>/dev/null || true)
1159
+ else
1160
+ lock_mtime=$(stat -c %Y "$lock_dir" 2>/dev/null || true)
1161
+ fi
1162
+ now=$(date +%s 2>/dev/null || true)
1163
+ if [[ "$lock_mtime" =~ ^[0-9]+$ && "$now" =~ ^[0-9]+$ && "$now" -ge "$lock_mtime" ]]; then
1164
+ printf '%s\n' $((now - lock_mtime))
1165
+ return 0
1166
+ fi
1167
+ printf '%s\n' 0
1168
+ return 0
1169
+ }
1170
+
1147
1171
  _setup_register_child_pid() {
1148
1172
  local pid="$1"
1149
1173
  [[ -n "$pid" ]] || return 0
@@ -1216,6 +1240,18 @@ _setup_acquire_noninteractive_setup_lock() {
1216
1240
  if [[ -r "$lock_dir/owner.pid" ]]; then
1217
1241
  owner_pid=$(tr -d '[:space:]' <"$lock_dir/owner.pid" 2>/dev/null || true)
1218
1242
  fi
1243
+ if [[ -z "$owner_pid" ]]; then
1244
+ local _lock_age="0"
1245
+ _lock_age=$(_setup_lock_dir_age_seconds "$lock_dir")
1246
+ if [[ "$_lock_age" -le 300 ]]; then
1247
+ print_error "Another setup.sh --non-interactive process is acquiring the deploy lock (lock: ${lock_dir}, age ${_lock_age}s). Exiting to avoid overlapping deployments."
1248
+ return 75
1249
+ fi
1250
+ print_warning "Removing stale setup.sh --non-interactive lock with no owner at ${lock_dir} (age ${_lock_age}s)"
1251
+ rm -rf "$lock_dir" 2>/dev/null || true
1252
+ attempts=$((attempts + 1))
1253
+ continue
1254
+ fi
1219
1255
  if _setup_lock_pid_alive "$owner_pid"; then
1220
1256
  [[ -r "$lock_dir/command" ]] && owner_cmd=$(tr '\n' ' ' <"$lock_dir/command" 2>/dev/null || true)
1221
1257
  # Build actionable diagnostics: elapsed time since lock was acquired