aidevops 3.8.95 → 3.8.96

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.8.95
1
+ 3.8.96
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.8.95
8
+ # Version: 3.8.96
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.8.95",
3
+ "version": "3.8.96",
4
4
  "description": "AI DevOps Framework - AI-assisted development workflows, code quality, and deployment automation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -499,6 +499,90 @@ _build_pulse_headless_env_xml() {
499
499
  return 0
500
500
  }
501
501
 
502
+ # Read user-owned plist env override file and emit XML key/string pairs
503
+ # for the matching label's env vars. Keys prefixed with _ are skipped
504
+ # (used as comments in the JSON template).
505
+ #
506
+ # Args: $1=plist_label (e.g. "com.aidevops.aidevops-supervisor-pulse")
507
+ # $2=override_file (absolute path; default ~/.agents/configs/plist-env-overrides.json)
508
+ # $3=indent (string to prepend each line; default "\t\t")
509
+ #
510
+ # Returns 0 on success (including empty result when label not found).
511
+ # Prints WARN to stderr and returns 0 when file is present but malformed.
512
+ # Emits nothing when file is absent.
513
+ _build_plist_env_overrides_xml() {
514
+ local _label="$1"
515
+ local _override_file="${2:-$HOME/.aidevops/agents/configs/plist-env-overrides.json}"
516
+ local _indent="${3:- }"
517
+
518
+ # Missing file is the normal case (user has not created the override file yet)
519
+ [[ -f "$_override_file" ]] || return 0
520
+
521
+ # Require jq — without it we cannot parse JSON safely
522
+ if ! command -v jq >/dev/null 2>&1; then
523
+ echo "[schedulers] WARN: jq not found; skipping plist-env-overrides.json injection" >&2
524
+ return 0
525
+ fi
526
+
527
+ # Validate JSON
528
+ if ! jq empty "$_override_file" 2>/dev/null; then
529
+ echo "[schedulers] WARN: plist-env-overrides.json is malformed; skipping injection (file: $_override_file)" >&2
530
+ return 0
531
+ fi
532
+
533
+ # Extract key=value pairs for the matching label; skip _ prefixed keys
534
+ local _pairs
535
+ _pairs=$(jq -r --arg label "$_label" '
536
+ .[$label] // {} |
537
+ to_entries[] |
538
+ select(.key | startswith("_") | not) |
539
+ "\(.key)=\(.value)"
540
+ ' "$_override_file" 2>/dev/null) || return 0
541
+
542
+ [[ -z "$_pairs" ]] && return 0
543
+
544
+ local _line _key _val _xml_key _xml_val
545
+ while IFS= read -r _line; do
546
+ [[ -z "$_line" ]] && continue
547
+ _key="${_line%%=*}"
548
+ _val="${_line#*=}"
549
+ _xml_key=$(_xml_escape "$_key")
550
+ _xml_val=$(_xml_escape "$_val")
551
+ printf '%s<key>%s</key>\n%s<string>%s</string>\n' \
552
+ "$_indent" "$_xml_key" "$_indent" "$_xml_val"
553
+ done <<<"$_pairs"
554
+
555
+ return 0
556
+ }
557
+
558
+ # Log which env var overrides were injected from plist-env-overrides.json for a label.
559
+ # Prints to stdout (setup.sh output). No-op when file absent or label not found.
560
+ # Args: $1=plist_label, $2=override_file (optional)
561
+ _log_plist_env_overrides() {
562
+ local _label="$1"
563
+ local _override_file="${2:-$HOME/.aidevops/agents/configs/plist-env-overrides.json}"
564
+
565
+ [[ -f "$_override_file" ]] || return 0
566
+ command -v jq >/dev/null 2>&1 || return 0
567
+ jq empty "$_override_file" 2>/dev/null || return 0
568
+
569
+ local _keys
570
+ _keys=$(jq -r --arg label "$_label" '
571
+ .[$label] // {} |
572
+ keys[] |
573
+ select(startswith("_") | not)
574
+ ' "$_override_file" 2>/dev/null) || return 0
575
+
576
+ [[ -z "$_keys" ]] && return 0
577
+
578
+ local _count
579
+ _count=$(echo "$_keys" | wc -l | tr -d ' ')
580
+ local _keys_inline
581
+ _keys_inline=$(echo "$_keys" | tr '\n' ' ' | sed 's/ $//')
582
+ print_info " plist-env-overrides: injected ${_count} var(s) into ${_label}: ${_keys_inline}"
583
+ return 0
584
+ }
585
+
502
586
  # Generate the full pulse launchd plist XML content.
503
587
  # Args: $1=pulse_label, $2=wrapper_script, $3=opencode_bin
504
588
  # Prints the complete plist XML to stdout.
@@ -538,6 +622,12 @@ _generate_pulse_plist_content() {
538
622
  local _pulse_interval_sec
539
623
  _pulse_interval_sec=$(_read_pulse_interval_seconds)
540
624
 
625
+ # Inject user-owned plist env overrides (GH#20563 / t2759).
626
+ # Reads ~/.aidevops/agents/configs/plist-env-overrides.json when present.
627
+ # Missing file or label not found → emits nothing (no-op, safe default).
628
+ local _env_overrides_xml
629
+ _env_overrides_xml=$(_build_plist_env_overrides_xml "$pulse_label")
630
+
541
631
  cat <<PLIST
542
632
  <?xml version="1.0" encoding="UTF-8"?>
543
633
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -569,7 +659,7 @@ _generate_pulse_plist_content() {
569
659
  <key>PULSE_STALE_THRESHOLD</key>
570
660
  <string>${PULSE_STALE_THRESHOLD_SECONDS}</string>
571
661
  ${_headless_xml_env}
572
- </dict>
662
+ ${_env_overrides_xml} </dict>
573
663
  <key>SoftResourceLimits</key>
574
664
  <dict>
575
665
  <key>NumberOfFiles</key>
@@ -614,6 +704,8 @@ _install_pulse_launchd() {
614
704
  else
615
705
  print_info "Supervisor pulse enabled (launchd, every ${_interval_label})"
616
706
  fi
707
+ # Log any user-provided env var overrides that were injected (GH#20563 / t2759)
708
+ _log_plist_env_overrides "$pulse_label"
617
709
  else
618
710
  print_warning "Failed to load supervisor pulse LaunchAgent"
619
711
  fi
@@ -388,6 +388,44 @@ setup_shell_linting_tools() {
388
388
  return 0
389
389
  }
390
390
 
391
+ setup_setsid_advisory() {
392
+ # setsid is required to detach pulse workers into their own process group
393
+ # (t2757, GH#20561). Without it, workers inherit pulse's PGID and are
394
+ # killed by any PG-scoped signal (launchd unload, restart chain).
395
+ #
396
+ # Linux: setsid ships with util-linux (present on all mainstream distros).
397
+ # macOS: available from macOS 12+ at /usr/bin/setsid. Older versions need
398
+ # util-linux via Homebrew (brew install util-linux).
399
+ if command -v setsid >/dev/null 2>&1; then
400
+ local setsid_path
401
+ setsid_path="$(command -v setsid)"
402
+ print_success "setsid found at $setsid_path (worker process-group isolation enabled)"
403
+ return 0
404
+ fi
405
+
406
+ # setsid missing — emit an advisory; it's a quality-of-life improvement,
407
+ # not a hard requirement (pulse falls back to nohup-only).
408
+ print_warning "setsid not found — pulse workers will share the pulse process group"
409
+ echo " Impact: a pulse restart or launchd unload may kill in-flight workers"
410
+ echo " (GH#20561 / t2757: worker survived 3/4 dispatches without setsid isolation)"
411
+ echo ""
412
+ if [[ "$(uname)" == "Darwin" ]]; then
413
+ if command -v brew >/dev/null 2>&1; then
414
+ echo " Install: brew install util-linux"
415
+ else
416
+ echo " Install Homebrew first, then: brew install util-linux"
417
+ echo " Or upgrade to macOS 12+ where /usr/bin/setsid ships by default"
418
+ fi
419
+ else
420
+ echo " Install: sudo apt install util-linux # Debian/Ubuntu"
421
+ echo " sudo dnf install util-linux # Fedora/RHEL"
422
+ echo " sudo pacman -S util-linux # Arch"
423
+ fi
424
+ echo ""
425
+
426
+ return 0
427
+ }
428
+
391
429
  setup_shellcheck_wrapper() {
392
430
  # Replace the real shellcheck binary with our wrapper script to prevent
393
431
  # --external-sources from causing exponential memory growth (GH#2915).
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.8.95
15
+ # Version: 3.8.96
16
16
  #
17
17
  # Quick Install:
18
18
  # npm install -g aidevops && aidevops update (recommended)