aidevops 3.5.543 → 3.5.544

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.5.543
1
+ 3.5.544
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.5.543
6
+ # Version: 3.5.544
7
7
 
8
8
  set -euo pipefail
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aidevops",
3
- "version": "3.5.543",
3
+ "version": "3.5.544",
4
4
  "description": "AI DevOps Framework - AI-assisted development workflows, code quality, and deployment automation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -215,13 +215,11 @@ setup_supervisor_pulse() {
215
215
  return 0
216
216
  }
217
217
 
218
- # Install supervisor pulse via launchd (macOS)
219
- _install_pulse_launchd() {
218
+ # Clean up old/legacy pulse launchd plists before reinstalling.
219
+ # Args: $1=pulse_label, $2=pulse_plist path
220
+ _cleanup_old_pulse_plists() {
220
221
  local pulse_label="$1"
221
- local wrapper_script="$2"
222
- local opencode_bin="$3"
223
- local _pulse_installed="$4"
224
- local pulse_plist="$HOME/Library/LaunchAgents/${pulse_label}.plist"
222
+ local pulse_plist="$2"
225
223
 
226
224
  # Unload old plist if upgrading
227
225
  if _launchd_has_agent "$pulse_label"; then
@@ -235,21 +233,18 @@ _install_pulse_launchd() {
235
233
  launchctl unload "$old_plist" || true
236
234
  rm -f "$old_plist"
237
235
  fi
236
+ return 0
237
+ }
238
238
 
239
- # XML-escape paths for safe plist embedding (prevents injection
240
- # if $HOME or paths contain &, <, > characters)
241
- local _xml_wrapper_script _xml_home _xml_opencode_bin _xml_pulse_dir _xml_path
239
+ # Build XML environment variable fragment for headless model overrides.
240
+ # Reads configured overrides and emits XML key/string pairs for plist embedding.
241
+ # Prints the XML fragment to stdout (may be empty if no overrides configured).
242
+ _build_pulse_headless_env_xml() {
242
243
  local _headless_xml_env=""
243
244
  local _configured_headless_models _configured_pulse_model
244
245
  _configured_headless_models=$(_resolve_headless_models_override)
245
246
  _configured_pulse_model=$(_resolve_pulse_model_override)
246
- _xml_wrapper_script=$(_xml_escape "$wrapper_script")
247
- _xml_home=$(_xml_escape "$HOME")
248
- _xml_opencode_bin=$(_xml_escape "$opencode_bin")
249
- # Use neutral workspace path for PULSE_DIR so supervisor sessions
250
- # are not associated with any specific managed repo (GH#5136).
251
- _xml_pulse_dir=$(_xml_escape "${HOME}/.aidevops/.agent-workspace")
252
- _xml_path=$(_xml_escape "$PATH")
247
+
253
248
  if [[ -n "$_configured_headless_models" ]]; then
254
249
  local _xml_headless_models
255
250
  _xml_headless_models=$(_xml_escape "$_configured_headless_models")
@@ -275,8 +270,33 @@ _install_pulse_launchd() {
275
270
  _headless_xml_env+=$'\t\t'"<string>${_xml_headless_allowlist}</string>"
276
271
  fi
277
272
 
278
- # Write the plist (always regenerated to pick up config changes)
279
- cat >"$pulse_plist" <<PLIST
273
+ printf '%s' "$_headless_xml_env"
274
+ return 0
275
+ }
276
+
277
+ # Generate the full pulse launchd plist XML content.
278
+ # Args: $1=pulse_label, $2=wrapper_script, $3=opencode_bin
279
+ # Prints the complete plist XML to stdout.
280
+ _generate_pulse_plist_content() {
281
+ local pulse_label="$1"
282
+ local wrapper_script="$2"
283
+ local opencode_bin="$3"
284
+
285
+ # XML-escape paths for safe plist embedding (prevents injection
286
+ # if $HOME or paths contain &, <, > characters)
287
+ local _xml_wrapper_script _xml_home _xml_opencode_bin _xml_pulse_dir _xml_path
288
+ _xml_wrapper_script=$(_xml_escape "$wrapper_script")
289
+ _xml_home=$(_xml_escape "$HOME")
290
+ _xml_opencode_bin=$(_xml_escape "$opencode_bin")
291
+ # Use neutral workspace path for PULSE_DIR so supervisor sessions
292
+ # are not associated with any specific managed repo (GH#5136).
293
+ _xml_pulse_dir=$(_xml_escape "${HOME}/.aidevops/.agent-workspace")
294
+ _xml_path=$(_xml_escape "$PATH")
295
+
296
+ local _headless_xml_env
297
+ _headless_xml_env=$(_build_pulse_headless_env_xml)
298
+
299
+ cat <<PLIST
280
300
  <?xml version="1.0" encoding="UTF-8"?>
281
301
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
282
302
  <plist version="1.0">
@@ -315,6 +335,21 @@ _install_pulse_launchd() {
315
335
  </dict>
316
336
  </plist>
317
337
  PLIST
338
+ return 0
339
+ }
340
+
341
+ # Install supervisor pulse via launchd (macOS)
342
+ _install_pulse_launchd() {
343
+ local pulse_label="$1"
344
+ local wrapper_script="$2"
345
+ local opencode_bin="$3"
346
+ local _pulse_installed="$4"
347
+ local pulse_plist="$HOME/Library/LaunchAgents/${pulse_label}.plist"
348
+
349
+ _cleanup_old_pulse_plists "$pulse_label" "$pulse_plist"
350
+
351
+ # Write the plist (always regenerated to pick up config changes)
352
+ _generate_pulse_plist_content "$pulse_label" "$wrapper_script" "$opencode_bin" >"$pulse_plist"
318
353
 
319
354
  if launchctl load "$pulse_plist"; then
320
355
  if [[ "$_pulse_installed" == "true" ]]; then
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.5.543
13
+ # Version: 3.5.544
14
14
  #
15
15
  # Quick Install:
16
16
  # npm install -g aidevops && aidevops update (recommended)
@@ -500,32 +500,24 @@ create_backup_with_rotation() {
500
500
  local backup_name="$2"
501
501
  local backup_base="$HOME/.aidevops/${backup_name}-backups"
502
502
  local backup_dir
503
- local backup_target
504
503
  backup_dir="$backup_base/$(date +%Y%m%d_%H%M%S)"
505
- backup_target="$backup_dir/$(basename "$source_path")"
506
504
 
507
505
  # Create backup directory
508
506
  mkdir -p "$backup_dir"
509
507
 
510
- # Copy source to backup
508
+ # Copy source to backup (tolerant of broken symlinks / missing entries)
511
509
  if [[ -d "$source_path" ]]; then
512
- mkdir -p "$backup_target"
513
- if command -v rsync >/dev/null 2>&1; then
514
- local rsync_status=0
515
- if rsync -a "$source_path/" "$backup_target/"; then
516
- rsync_status=0
517
- else
518
- rsync_status=$?
519
- fi
520
-
521
- if [[ "$rsync_status" -eq 24 ]]; then
522
- print_warning "Backup completed with missing source entries skipped: $source_path"
523
- elif [[ "$rsync_status" -ne 0 ]]; then
524
- print_error "Backup failed for $source_path (rsync exit $rsync_status)"
525
- return "$rsync_status"
510
+ if command -v rsync >/dev/null 2>&1 && rsync --help 2>&1 | grep -q -- '--ignore-missing-args'; then
511
+ # rsync >= 3.1.0: --ignore-missing-args skips missing/broken entries gracefully
512
+ if ! rsync -a --ignore-missing-args "$source_path/" "$backup_dir/$(basename "$source_path")/" 2>/dev/null; then
513
+ print_warning "Backup had partial failures (broken symlinks?), continuing"
526
514
  fi
527
515
  else
528
- cp -R "$source_path" "$backup_dir/"
516
+ # Fallback: cp -R may fail on broken symlinks under set -e,
517
+ # so run in a subshell that tolerates errors
518
+ if ! (cp -R "$source_path" "$backup_dir/" 2>/dev/null); then
519
+ print_warning "Backup had partial failures (broken symlinks?), continuing"
520
+ fi
529
521
  fi
530
522
  elif [[ -f "$source_path" ]]; then
531
523
  cp "$source_path" "$backup_dir/"