aidevops 3.34.9 → 3.34.10

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/README.md CHANGED
@@ -25,7 +25,7 @@ token efficiency, and quality control built in.**
25
25
  [![Maintainability](https://qlty.sh/gh/marcusquinn/projects/aidevops/maintainability.svg)](https://qlty.sh/gh/marcusquinn/projects/aidevops)
26
26
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/2b1adbd66c454dae92234341e801b984)](https://app.codacy.com/gh/marcusquinn/aidevops/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
27
27
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
28
- [![Version](https://img.shields.io/badge/Version-3.34.9-blue.svg)](https://github.com/marcusquinn/aidevops/releases)
28
+ [![Version](https://img.shields.io/badge/Version-3.34.10-blue.svg)](https://github.com/marcusquinn/aidevops/releases)
29
29
  [![npm version](https://img.shields.io/npm/v/aidevops)](https://www.npmjs.com/package/aidevops)
30
30
  [![Homebrew](https://img.shields.io/badge/homebrew-marcusquinn%2Ftap-orange)](https://github.com/marcusquinn/homebrew-tap)
31
31
 
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.34.9
1
+ 3.34.10
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.34.9
8
+ # Version: 3.34.10
9
9
 
10
10
  set -euo pipefail
11
11
 
@@ -310,7 +310,17 @@ _run_update_source_access_reconciliation() {
310
310
  return 0
311
311
  fi
312
312
 
313
- print_warning "AIDEVOPS_DEFERRED_ACTION action=source-access-reconcile command='aidevops setup --scope source-access'"
313
+ if [[ -t 0 && -t 1 ]]; then
314
+ print_info "Reconciling the protected source-access broker..."
315
+ if AIDEVOPS_SOURCE_ACCESS_INTERACTIVE=true bash "$INSTALL_DIR/setup.sh" --stage source-access; then
316
+ print_success "Protected source-access broker reconciled"
317
+ return 0
318
+ fi
319
+ print_warning "Source-access broker maintenance was blocked; it will retry during the next interactive update"
320
+ return 0
321
+ fi
322
+
323
+ print_warning "Source-access broker maintenance requires an attached terminal for privilege confirmation; the next interactive update will retry automatically"
314
324
  return 0
315
325
  }
316
326
 
@@ -347,19 +357,10 @@ cmd_update_help() {
347
357
  }
348
358
 
349
359
  cmd_update() {
350
- # Update is operational, not compositional. Do not let any reachable Git,
351
- # package-manager, migration, or setup subprocess inherit an editor or pager.
352
- # Local declarations restore the caller's environment when this function exits.
353
- local EDITOR=/usr/bin/false
354
- local VISUAL=/usr/bin/false
355
- local GIT_EDITOR=/usr/bin/false
356
- local GIT_SEQUENCE_EDITOR=/usr/bin/false
357
- local GIT_PAGER=cat
358
- local PAGER=cat
359
- local GIT_TERMINAL_PROMPT=0
360
+ local EDITOR=/usr/bin/false VISUAL=/usr/bin/false GIT_EDITOR=/usr/bin/false
361
+ local GIT_SEQUENCE_EDITOR=/usr/bin/false GIT_PAGER="cat" PAGER="cat" GIT_TERMINAL_PROMPT=0
360
362
  export EDITOR VISUAL GIT_EDITOR GIT_SEQUENCE_EDITOR GIT_PAGER PAGER GIT_TERMINAL_PROMPT
361
363
  local skip_project_sync=false
362
- local reconcile_repo_verify=false
363
364
  local update_output_mode="${AIDEVOPS_OUTPUT_MODE:-auto}"
364
365
  local arg
365
366
  for arg in "$@"; do
@@ -375,122 +376,128 @@ cmd_update() {
375
376
  current_version=$(get_version)
376
377
  print_info "Current version: $current_version"
377
378
  print_info "Fetching latest version..."
379
+ _AIDEVOPS_UPDATE_RECONCILE_REPO_VERIFY=false
380
+ _update_install_framework "$current_version" "$update_output_mode" || return 1
381
+ _update_finish "$skip_project_sync"
382
+ return 0
383
+ }
378
384
 
385
+ _update_install_framework() {
386
+ local current_version="$1" update_output_mode="$2"
379
387
  if check_dir "$INSTALL_DIR/.git"; then
380
- cd "$INSTALL_DIR" || exit 1
381
- if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then
382
- print_error "Refusing to update: tracked local changes exist in $INSTALL_DIR"
383
- git status --short
384
- print_info "Commit or stash these changes, then rerun aidevops update."
385
- return 1
386
- fi
387
- local current_branch
388
- current_branch=$(git branch --show-current 2>/dev/null || echo "")
389
- if [[ "$current_branch" != "main" ]]; then
390
- print_info "Switching to main branch..."
391
- if ! git checkout main --quiet 2>/dev/null && ! git checkout -b main origin/main --quiet 2>/dev/null; then
392
- print_error "Failed to switch to main; refusing to update the active '$current_branch' branch."
393
- return 1
394
- fi
395
- fi
396
- local local_hash
397
- local_hash=$(git rev-parse HEAD) || return 1
398
- if ! _update_fetch_main main; then
399
- print_error "Failed to fetch origin/main; no update was applied."
400
- return 1
401
- fi
402
- local remote_hash
403
- remote_hash=$(git rev-parse origin/main) || return 1
404
- if [[ "$local_hash" != "$remote_hash" ]] && git merge-base --is-ancestor "$remote_hash" "$local_hash" 2>/dev/null; then
405
- print_error "Refusing to update: local commits exist on main."
406
- print_info "Preserve or reconcile the local history in $INSTALL_DIR, then rerun aidevops update."
388
+ _update_existing_install "$current_version" "$update_output_mode" || return 1
389
+ else
390
+ _update_fresh_install || return 1
391
+ fi
392
+ return 0
393
+ }
394
+
395
+ _update_existing_install() {
396
+ local current_version="$1" update_output_mode="$2"
397
+ cd "$INSTALL_DIR" || exit 1
398
+ if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then
399
+ print_error "Refusing to update: tracked local changes exist in $INSTALL_DIR"
400
+ git status --short
401
+ print_info "Commit or stash these changes, then rerun aidevops update."
402
+ return 1
403
+ fi
404
+ local current_branch
405
+ current_branch=$(git branch --show-current 2>/dev/null || echo "")
406
+ if [[ "$current_branch" != "main" ]]; then
407
+ print_info "Switching to main branch..."
408
+ if ! git checkout main --quiet 2>/dev/null && ! git checkout -b main origin/main --quiet 2>/dev/null; then
409
+ print_error "Failed to switch to main; refusing to update the active '$current_branch' branch."
407
410
  return 1
408
411
  fi
409
- if [[ "$local_hash" == "$remote_hash" ]]; then
410
- print_success "Framework already up to date!"
411
- local repo_version deployed_version
412
- repo_version=$(cat "$INSTALL_DIR/VERSION" 2>/dev/null || echo "unknown")
413
- deployed_version=$(cat "$HOME/.aidevops/agents/VERSION" 2>/dev/null || echo "none")
414
- if [[ "$repo_version" != "$deployed_version" ]]; then
415
- print_warning "Deployed agents ($deployed_version) don't match repo ($repo_version)"
416
- print_info "Re-running incremental setup to sync agents..."
417
- _run_update_setup_transaction "$update_output_mode" "$local_hash" || return 1
418
- else
419
- # t2706: VERSION matches but .deployed-sha may lag HEAD when
420
- # fixes land between releases. Detect and redeploy on framework
421
- # code drift (inline so bootstrap doesn't depend on the deployed
422
- # aidevops-update-check.sh already carrying the same check).
423
- # Docs-only drift is intentionally skipped — no runtime impact.
424
- local stamp_file="$HOME/.aidevops/.deployed-sha"
425
- if [[ -f "$stamp_file" ]]; then
426
- local deployed_sha has_code_drift=0
427
- deployed_sha=$(tr -d '[:space:]' <"$stamp_file" 2>/dev/null) || deployed_sha=""
428
- if [[ -n "$deployed_sha" && "$deployed_sha" != "$local_hash" ]]; then
429
- if _update_repo_verify_files_changed "$deployed_sha" "$local_hash"; then reconcile_repo_verify=true; fi
430
- # Per Gemini code-review on PR #20342: use git's path filter +
431
- # `grep -q .` to detect drift across the full set of deploy-affecting
432
- # paths (not just .agents/ subdirs — also setup.sh, .agents/scripts/setup/modules/,
433
- # and aidevops.sh itself, which are deployed/sourced by setup).
434
- if git -C "$INSTALL_DIR" diff --name-only "$deployed_sha" "$local_hash" -- \
435
- .agents/scripts/ .agents/agents/ .agents/workflows/ .agents/prompts/ .agents/hooks/ \
436
- setup.sh .agents/scripts/setup/modules/ aidevops.sh 2>/dev/null | grep -q .; then
437
- has_code_drift=1
438
- fi
439
- if [[ "$has_code_drift" -eq 1 ]]; then
440
- print_warning "Deployed scripts drifted (${deployed_sha:0:7}→${local_hash:0:7})"
441
- print_info "Re-running incremental setup to deploy latest scripts..."
442
- _run_update_setup_transaction "$update_output_mode" "$local_hash" || return 1
443
- fi
444
- # GH#21735: workflow templates can change between
445
- # releases without triggering has_code_drift (templates
446
- # live outside the deploy-affecting paths). Check the
447
- # template subset separately and surface drift.
448
- _update_check_workflow_drift "$deployed_sha" "$local_hash"
449
- fi
450
- fi
451
- fi
452
- else
453
- print_info "Applying latest changes..."
454
- local old_hash
455
- old_hash="$local_hash"
456
- if [[ "${_AIDEVOPS_UPDATE_CANONICAL_FAST_FORWARDED:-false}" == "true" ]]; then
457
- :
458
- elif git merge --ff-only "$remote_hash" --quiet; then
459
- :
460
- else
461
- print_error "Fast-forward update failed; preserving local history."
462
- print_info "Review $INSTALL_DIR, resolve the divergence, then rerun aidevops update."
463
- return 1
464
- fi
465
- local new_version new_hash
466
- new_version=$(get_version)
467
- new_hash=$(git rev-parse HEAD)
468
- if [[ "$new_hash" != "$remote_hash" ]]; then
469
- print_error "Updated HEAD does not match the fetched origin/main commit; refusing to run setup."
470
- return 1
471
- fi
472
- if [[ "$old_hash" != "$new_hash" ]]; then
473
- if _update_repo_verify_files_changed "$old_hash" "$new_hash"; then reconcile_repo_verify=true; fi
474
- _update_render_changelog "$old_hash" "$new_hash" "$current_version"
475
- # GH#21735: surface workflow template drift so the
476
- # operator can resync downstream callers before CI bites.
477
- _update_check_workflow_drift "$old_hash" "$new_hash"
478
- fi
479
- echo ""
480
- # Verify supply chain integrity before applying changes
481
- _update_verify_signature
482
- echo ""
483
- print_info "Running incremental setup to apply changes (falls back to full setup if needed)..."
484
- _run_update_setup_transaction "$update_output_mode" "$new_hash" || return 1
485
- print_success "Updated to version $new_version (agents deployed)"
486
- fi
412
+ fi
413
+ local local_hash remote_hash
414
+ local_hash=$(git rev-parse HEAD) || return 1
415
+ if ! _update_fetch_main main; then
416
+ print_error "Failed to fetch origin/main; no update was applied."
417
+ return 1
418
+ fi
419
+ remote_hash=$(git rev-parse origin/main) || return 1
420
+ if [[ "$local_hash" != "$remote_hash" ]] && git merge-base --is-ancestor "$remote_hash" "$local_hash" 2>/dev/null; then
421
+ print_error "Refusing to update: local commits exist on main."
422
+ print_info "Preserve or reconcile the local history in $INSTALL_DIR, then rerun aidevops update."
423
+ return 1
424
+ fi
425
+ if [[ "$local_hash" == "$remote_hash" ]]; then
426
+ _update_already_current "$local_hash" "$update_output_mode"
487
427
  else
488
- _update_fresh_install || return 1
428
+ _update_apply_remote "$local_hash" "$remote_hash" "$current_version" "$update_output_mode"
489
429
  fi
430
+ return 0
431
+ }
432
+
433
+ _update_already_current() {
434
+ local local_hash="$1" update_output_mode="$2"
435
+ print_success "Framework already up to date!"
436
+ local repo_version deployed_version
437
+ repo_version=$(cat "$INSTALL_DIR/VERSION" 2>/dev/null || echo "unknown")
438
+ deployed_version=$(cat "$HOME/.aidevops/agents/VERSION" 2>/dev/null || echo "none")
439
+ if [[ "$repo_version" != "$deployed_version" ]]; then
440
+ print_warning "Deployed agents ($deployed_version) don't match repo ($repo_version)"
441
+ print_info "Re-running incremental setup to sync agents..."
442
+ _run_update_setup_transaction "$update_output_mode" "$local_hash"
443
+ return $?
444
+ fi
445
+ local stamp_file="$HOME/.aidevops/.deployed-sha" deployed_sha=""
446
+ [[ -f "$stamp_file" ]] || return 0
447
+ deployed_sha=$(tr -d '[:space:]' <"$stamp_file" 2>/dev/null) || deployed_sha=""
448
+ [[ -n "$deployed_sha" && "$deployed_sha" != "$local_hash" ]] || return 0
449
+ if _update_repo_verify_files_changed "$deployed_sha" "$local_hash"; then _AIDEVOPS_UPDATE_RECONCILE_REPO_VERIFY=true; fi
450
+ if git -C "$INSTALL_DIR" diff --name-only "$deployed_sha" "$local_hash" -- .agents/scripts/ .agents/agents/ .agents/workflows/ .agents/prompts/ .agents/hooks/ setup.sh .agents/scripts/setup/modules/ aidevops.sh 2>/dev/null | grep -q .; then
451
+ print_warning "Deployed scripts drifted (${deployed_sha:0:7}→${local_hash:0:7})"
452
+ print_info "Re-running incremental setup to deploy latest scripts..."
453
+ _run_update_setup_transaction "$update_output_mode" "$local_hash" || return 1
454
+ fi
455
+ _update_check_workflow_drift "$deployed_sha" "$local_hash"
456
+ return 0
457
+ }
458
+
459
+ _update_apply_remote() {
460
+ local old_hash="$1" remote_hash="$2" current_version="$3" update_output_mode="$4"
461
+ print_info "Applying latest changes..."
462
+ if [[ "${_AIDEVOPS_UPDATE_CANONICAL_FAST_FORWARDED:-false}" != "true" ]] && ! git merge --ff-only "$remote_hash" --quiet; then
463
+ print_error "Fast-forward update failed; preserving local history."
464
+ print_info "Review $INSTALL_DIR, resolve the divergence, then rerun aidevops update."
465
+ return 1
466
+ fi
467
+ local new_version new_hash
468
+ new_version=$(get_version)
469
+ new_hash=$(git rev-parse HEAD)
470
+ if [[ "$new_hash" != "$remote_hash" ]]; then
471
+ print_error "Updated HEAD does not match the fetched origin/main commit; refusing to run setup."
472
+ return 1
473
+ fi
474
+ if [[ "$old_hash" != "$new_hash" ]]; then
475
+ if _update_repo_verify_files_changed "$old_hash" "$new_hash"; then _AIDEVOPS_UPDATE_RECONCILE_REPO_VERIFY=true; fi
476
+ _update_render_changelog "$old_hash" "$new_hash" "$current_version"
477
+ _update_check_workflow_drift "$old_hash" "$new_hash"
478
+ fi
479
+ echo ""
480
+ _update_verify_signature
481
+ echo ""
482
+ print_info "Running incremental setup to apply changes (falls back to full setup if needed)..."
483
+ _run_update_setup_transaction "$update_output_mode" "$new_hash" || return 1
484
+ print_success "Updated to version $new_version (agents deployed)"
485
+ return 0
486
+ }
487
+
488
+ _update_start_pulse() {
489
+ [[ "${AIDEVOPS_SKIP_PULSE_RESTART:-0}" != "1" ]] || return 0
490
+ local pulse_helper="${AGENTS_DIR}/scripts/pulse-lifecycle-helper.sh"
491
+ [[ -x "$pulse_helper" ]] && "$pulse_helper" start >/dev/null 2>&1 || print_warning "Pulse start failed (non-fatal)"
492
+ return 0
493
+ }
494
+
495
+ _update_finish() {
496
+ local skip_project_sync="$1"
490
497
 
491
498
  _run_update_source_access_reconciliation
492
499
  _update_sync_projects "$skip_project_sync" "$(get_version)"
493
- if [[ "$skip_project_sync" != "$_AIDEVOPS_UPDATE_TRUE" && "$reconcile_repo_verify" == "$_AIDEVOPS_UPDATE_TRUE" ]]; then
500
+ if [[ "$skip_project_sync" != "$_AIDEVOPS_UPDATE_TRUE" && "${_AIDEVOPS_UPDATE_RECONCILE_REPO_VERIFY:-false}" == "$_AIDEVOPS_UPDATE_TRUE" ]]; then
494
501
  _update_reconcile_repo_verify
495
502
  fi
496
503
  _update_check_homebrew
@@ -532,13 +539,7 @@ cmd_update() {
532
539
  # 'start' subcommand does not check it directly — only 'restart' and
533
540
  # 'restart-if-running' do). Non-fatal: a pulse start failure should
534
541
  # not fail the update.
535
- if [[ "${AIDEVOPS_SKIP_PULSE_RESTART:-0}" != "1" ]]; then
536
- local _pulse_helper="${AGENTS_DIR}/scripts/pulse-lifecycle-helper.sh"
537
- if [[ -x "$_pulse_helper" ]]; then
538
- "$_pulse_helper" start >/dev/null 2>&1 || print_warning "Pulse start failed (non-fatal)"
539
- fi
540
- fi
541
-
542
+ _update_start_pulse
542
543
  return 0
543
544
  }
544
545
 
@@ -1180,7 +1181,7 @@ _help_commands() {
1180
1181
  return 0
1181
1182
  }
1182
1183
 
1183
- _help_detailed_sections() {
1184
+ _help_security_sections() {
1184
1185
  echo "Security:"
1185
1186
  echo " aidevops security # Run ALL checks (posture + hygiene + supply chain)"
1186
1187
  echo " aidevops security posture # Interactive security posture setup (gopass, gh, SSH)"
@@ -1241,6 +1242,11 @@ _help_detailed_sections() {
1241
1242
  echo " aidevops client-format extract # 1. Re-extract constants"
1242
1243
  echo " aidevops client-format canary # 2. Verify against real CLI"
1243
1244
  echo ""
1245
+ return 0
1246
+ }
1247
+
1248
+ _help_detailed_sections_content() {
1249
+ _help_security_sections
1244
1250
  echo "Secrets:"
1245
1251
  echo " aidevops secret set NAME # Store a secret (hidden input)"
1246
1252
  echo " aidevops secret list # List secret names (never values)"
@@ -1249,26 +1255,7 @@ _help_detailed_sections() {
1249
1255
  echo " aidevops secret import # Import from credentials.sh to gopass"
1250
1256
  echo " aidevops secret status # Show backend status"
1251
1257
  echo ""
1252
- echo "Vault:"
1253
- echo " aidevops vault init # Create local encrypted Vault metadata"
1254
- echo " aidevops vault status # Show uninitialized/locked/unlocked/corrupted"
1255
- echo " aidevops vault unlock # Unlock into an in-memory local broker"
1256
- echo " aidevops vault lock # Stop broker and forget in-memory keys"
1257
- echo " aidevops vault read NAME # Read protected data through broker"
1258
- echo " aidevops vault update NAME # Encrypt stdin value through broker"
1259
- echo ""
1260
- echo "GitHub App Auth:"
1261
- echo " aidevops github-app-auth status --json # Show active auth mode and budgets"
1262
- echo " aidevops github-app-auth route issue-list # Explain route decision"
1263
- echo " aidevops github-app-auth rate-limit --json # Show cached per-pool budgets"
1264
- echo ""
1265
- echo "Feature Toggles:"
1266
- echo " aidevops config list # List all toggles with current values"
1267
- echo " aidevops config get <key> # Get a toggle value"
1268
- echo " aidevops config set <k> <v> # Set a toggle (true/false)"
1269
- echo " aidevops config reset [key] # Reset toggle(s) to defaults"
1270
- echo " aidevops config path # Show config file path"
1271
- echo ""
1258
+ _help_vault_and_config_sections
1272
1259
  echo "Knowledge Plane:"
1273
1260
  echo " aidevops knowledge init repo # Provision _knowledge/ in current repo"
1274
1261
  echo " aidevops knowledge init personal # Provision at ~/.aidevops/.agent-workspace/knowledge/"
@@ -1343,6 +1330,11 @@ _help_detailed_sections() {
1343
1330
  return 0
1344
1331
  }
1345
1332
 
1333
+ _help_detailed_sections() {
1334
+ _help_detailed_sections_content
1335
+ return 0
1336
+ }
1337
+
1346
1338
  _help_management_sections() {
1347
1339
  echo "Auto-Update:"
1348
1340
  echo " aidevops auto-update enable # Poll for updates every 10 min"
@@ -1830,48 +1822,81 @@ _cmd_client_format() {
1830
1822
  }
1831
1823
 
1832
1824
  # Main entry point
1825
+ _main_badges() {
1826
+ local subcommand="${1:-}"
1827
+ local sync_helper="badges-sync-helper.sh"
1828
+ case "$subcommand" in
1829
+ render)
1830
+ shift
1831
+ local helper="$HOME/.aidevops/agents/scripts/readme-badges-helper.sh"
1832
+ [[ -f "$helper" ]] || helper="$AGENTS_DIR/scripts/readme-badges-helper.sh"
1833
+ if [[ -f "$helper" ]]; then bash "$helper" render "$@"; else print_error "readme-badges-helper.sh not found. Run: aidevops update"; return 1; fi
1834
+ ;;
1835
+ check) shift; _dispatch_helper "badges-check-helper.sh" "badges-check-helper.sh" "$@" ;;
1836
+ sync) shift; _dispatch_helper "$sync_helper" "$sync_helper" "$@" ;;
1837
+ install) shift; _dispatch_helper "$sync_helper" "$sync_helper" --workflow-only "$@" ;;
1838
+ help | --help | -h | "")
1839
+ echo ""
1840
+ echo "aidevops badges — README badge block and repo metrics workflow management (t2975)"
1841
+ echo ""
1842
+ echo "Subcommands:"
1843
+ echo " render <slug> Print canonical badge block for a repo"
1844
+ echo " check [--repo SLUG] [--json] Detect badge drift across managed repos"
1845
+ echo " sync [--repo SLUG] [--apply] Inject badge block + generate metrics + install workflow"
1846
+ echo " install [--repo SLUG] [--apply] Install repo metrics refresh workflow only"
1847
+ echo ""
1848
+ echo "Options (check/sync/install):"
1849
+ echo " --repo SLUG Limit to a single repo"
1850
+ echo " --apply Actually perform the sync (default: dry-run)"
1851
+ echo " --json Machine-readable output"
1852
+ echo " --verbose Show diff summaries (check only)"
1853
+ echo ""
1854
+ echo "Examples:"
1855
+ echo " aidevops badges check # scan all repos for badge drift"
1856
+ echo " aidevops badges check --json | jq '.[]' # machine-readable output"
1857
+ echo " aidevops badges render owner/repo # print badge block"
1858
+ echo " aidevops badges sync # dry-run sync across all repos"
1859
+ echo " aidevops badges sync --repo owner/r --apply # apply to a single repo"
1860
+ echo " aidevops metrics generate [PATH] # generate local docs/metrics artifacts"
1861
+ echo ""
1862
+ ;;
1863
+ *) print_error "Unknown badges subcommand: $subcommand (try render|check|sync|install|help)"; return 1 ;;
1864
+ esac
1865
+ return 0
1866
+ }
1867
+
1833
1868
  main() {
1834
1869
  local command="${1:-help}"
1835
1870
  local check_workflows_helper="check-workflows-helper.sh"
1871
+ local update_help="help"
1836
1872
  shift || true
1837
-
1838
- # Help for inventory commands must bypass repository auto-detection and
1839
- # version checks. Those startup checks may read the repository registry,
1840
- # while help must remain bounded and side-effect-free.
1841
- if [[ "$command" == "check-workflows" || "$command" == "workflows" ]]; then
1842
- local arg
1843
- for arg in "$@"; do
1844
- case "$arg" in
1845
- -h | --help)
1846
- _dispatch_helper "$check_workflows_helper" "$check_workflows_helper" "$@"
1847
- return $?
1848
- ;;
1849
- esac
1850
- done
1851
- fi
1852
-
1853
- # Update help must return before startup checks or cmd_update(), which can
1854
- # inspect repositories, fetch remotes, deploy agents, and synchronize projects.
1855
1873
  if [[ "$command" == "update" || "$command" == "upgrade" || "$command" == "u" ]]; then
1856
1874
  local arg
1857
1875
  for arg in "$@"; do
1858
- case "$arg" in
1859
- help | -h | --help)
1860
- cmd_update_help
1861
- return $?
1862
- ;;
1863
- esac
1876
+ if [[ "$arg" == "$update_help" || "$arg" == "-h" || "$arg" == "--help" ]]; then cmd_update_help; return $?; fi
1864
1877
  done
1878
+ _main_check_unregistered "$command"
1879
+ cmd_update "$@"
1880
+ return $?
1865
1881
  fi
1866
-
1867
- # Auto-detect unregistered repo on any command (silent check)
1882
+ _main_early_help "$command" "$check_workflows_helper" "$@" && return 0
1868
1883
  _main_check_unregistered "$command"
1884
+ _main_check_version
1885
+ _main_dispatch "$command" "$check_workflows_helper" "$@"
1886
+ }
1869
1887
 
1870
- # Check if agents need updating (skip for update command itself)
1871
- if [[ "$command" != "update" && "$command" != "upgrade" && "$command" != "u" ]]; then
1872
- _main_check_version
1873
- fi
1888
+ _main_early_help() {
1889
+ local command="$1" check_workflows_helper="$2" arg
1890
+ shift 2
1891
+ for arg in "$@"; do
1892
+ if [[ "$command" == "check-workflows" || "$command" == "workflows" ]] && [[ "$arg" == "-h" || "$arg" == "--help" ]]; then _dispatch_helper "$check_workflows_helper" "$check_workflows_helper" "$@"; return $?; fi
1893
+ done
1894
+ return 1
1895
+ }
1874
1896
 
1897
+ _main_dispatch() {
1898
+ local command="$1" check_workflows_helper="$2"
1899
+ shift 2
1875
1900
  case "$command" in
1876
1901
  init | i) cmd_init "$@" ;;
1877
1902
  setup) cmd_setup "$@" ;;
@@ -1897,76 +1922,7 @@ main() {
1897
1922
  check-workflows | workflows) _dispatch_helper "$check_workflows_helper" "$check_workflows_helper" "$@" ;;
1898
1923
  sync-workflows) _dispatch_helper "sync-workflows-helper.sh" "sync-workflows-helper.sh" "$@" ;;
1899
1924
  metrics) _dispatch_helper "repo-metrics-helper.sh" "repo-metrics-helper.sh" "$@" ;;
1900
- badges)
1901
- # Badge management: render | check | sync | install (t2975)
1902
- # Bare 'aidevops badges' with no subcommand shows a usage summary.
1903
- # Subcommands:
1904
- # render <slug> — render canonical badge block for a repo
1905
- # check [--repo SLUG] [--json] [--verbose] — cross-repo drift check
1906
- # sync [--repo SLUG] [--apply] — inject badge block + generate metrics + install workflow
1907
- # install [--repo SLUG] [--apply] — install repo metrics refresh workflow only
1908
- local _badges_sub="${1:-help}"
1909
- local _badges_check_h="badges-check-helper.sh"
1910
- local _badges_sync_h="badges-sync-helper.sh"
1911
- case "$_badges_sub" in
1912
- render)
1913
- shift
1914
- local _render_helper
1915
- _render_helper=$(bash -c '
1916
- d="$HOME/.aidevops/agents/scripts/readme-badges-helper.sh"
1917
- l="'"$AGENTS_DIR"'/scripts/readme-badges-helper.sh"
1918
- [[ -f "$d" ]] && echo "$d" || echo "$l"
1919
- ')
1920
- if [[ -f "$_render_helper" ]]; then
1921
- bash "$_render_helper" render "$@"
1922
- else
1923
- print_error "readme-badges-helper.sh not found. Run: aidevops update"
1924
- exit 1
1925
- fi
1926
- ;;
1927
- check)
1928
- shift
1929
- _dispatch_helper "$_badges_check_h" "$_badges_check_h" "$@"
1930
- ;;
1931
- sync)
1932
- shift
1933
- _dispatch_helper "$_badges_sync_h" "$_badges_sync_h" "$@"
1934
- ;;
1935
- install)
1936
- shift
1937
- _dispatch_helper "$_badges_sync_h" "$_badges_sync_h" --workflow-only "$@"
1938
- ;;
1939
- help | --help | -h | "")
1940
- echo ""
1941
- echo "aidevops badges — README badge block and repo metrics workflow management (t2975)"
1942
- echo ""
1943
- echo "Subcommands:"
1944
- echo " render <slug> Print canonical badge block for a repo"
1945
- echo " check [--repo SLUG] [--json] Detect badge drift across managed repos"
1946
- echo " sync [--repo SLUG] [--apply] Inject badge block + generate metrics + install workflow"
1947
- echo " install [--repo SLUG] [--apply] Install repo metrics refresh workflow only"
1948
- echo ""
1949
- echo "Options (check/sync/install):"
1950
- echo " --repo SLUG Limit to a single repo"
1951
- echo " --apply Actually perform the sync (default: dry-run)"
1952
- echo " --json Machine-readable output"
1953
- echo " --verbose Show diff summaries (check only)"
1954
- echo ""
1955
- echo "Examples:"
1956
- echo " aidevops badges check # scan all repos for badge drift"
1957
- echo " aidevops badges check --json | jq '.[]' # machine-readable output"
1958
- echo " aidevops badges render owner/repo # print badge block"
1959
- echo " aidevops badges sync # dry-run sync across all repos"
1960
- echo " aidevops badges sync --repo owner/r --apply # apply to a single repo"
1961
- echo " aidevops metrics generate [PATH] # generate local docs/metrics artifacts"
1962
- echo ""
1963
- ;;
1964
- *)
1965
- print_error "Unknown badges subcommand: $_badges_sub (try render|check|sync|install|help)"
1966
- exit 1
1967
- ;;
1968
- esac
1969
- ;;
1925
+ badges) _main_badges "$@" ;;
1970
1926
  security) _cmd_security "$@" ;;
1971
1927
  doctor | doc) _dispatch_helper "doctor-helper.sh" "doctor-helper.sh" "$@" ;;
1972
1928
  detect | scan) cmd_detect ;;
@@ -1974,32 +1930,7 @@ main() {
1974
1930
  model-accounts-pool | map) _dispatch_helper "oauth-pool-helper.sh" "oauth-pool-helper.sh" "$@" ;;
1975
1931
  gpt56-context | gpt56_context) _dispatch_helper "gpt56-context-helper.sh" "gpt56-context-helper.sh" "$@" ;;
1976
1932
  astra-context | astra_context) _dispatch_helper "astra-context-helper.sh" "astra-context-helper.sh" "$@" ;;
1977
- cleanup)
1978
- local _cleanup_sub="${1:-help}"
1979
- case "$_cleanup_sub" in
1980
- branches | remote-branches)
1981
- shift || true
1982
- _dispatch_helper "remote-branch-cleanup-helper.sh" "remote-branch-cleanup-helper.sh" "$_cleanup_sub" "$@"
1983
- ;;
1984
- help | --help | -h | "")
1985
- echo "Usage: aidevops cleanup <branches|remote-branches> [options]"
1986
- echo ""
1987
- echo "Cleanup commands:"
1988
- echo " branches Audit stale remote branches (dry-run default)"
1989
- echo " remote-branches Alias for branches"
1990
- echo ""
1991
- echo "Options:"
1992
- echo " --repo PATH Repository path (default: current directory)"
1993
- echo " --remote NAME Remote to audit (default: origin)"
1994
- echo " --apply Delete safe candidates"
1995
- echo ""
1996
- ;;
1997
- *)
1998
- print_error "Unknown cleanup subcommand: $_cleanup_sub (try branches|remote-branches|help)"
1999
- exit 1
2000
- ;;
2001
- esac
2002
- ;;
1933
+ cleanup) _main_dispatch_cleanup "$@" ;;
2003
1934
  client-format) _cmd_client_format "$@" ;;
2004
1935
  github-app-auth | github-app | gh-auth) _dispatch_helper "github-app-auth-helper.sh" "github-app-auth-helper.sh" "$@" ;;
2005
1936
  opencode-db | oc-db) _dispatch_helper "opencode-db-maintenance-helper.sh" "opencode-db-maintenance-helper.sh" "$@" ;;
@@ -2021,12 +1952,7 @@ main() {
2021
1952
  worktree | wt) _dispatch_helper "worktree-helper.sh" "worktree-helper.sh" "$@" ;;
2022
1953
  issue) _dispatch_helper "interactive-session-helper.sh" "interactive-session-helper.sh" "$@" ;;
2023
1954
  signing) _dispatch_helper "signing-setup.sh" "signing-setup.sh" "$@" ;;
2024
- contributions | contrib)
2025
- # Bare `aidevops contributions` defaults to status (most common use).
2026
- # Other subcommands (seed, scan, stop, restart, install, uninstall) forward verbatim.
2027
- [[ $# -eq 0 ]] && set -- status
2028
- _dispatch_helper "contribution-watch-helper.sh" "contribution-watch-helper.sh" "$@"
2029
- ;;
1955
+ contributions | contrib) _main_dispatch_contributions "$@" ;;
2030
1956
  inbox)
2031
1957
  # Bare `aidevops inbox` defaults to status (most common use).
2032
1958
  [[ $# -eq 0 ]] && set -- status
@@ -2050,44 +1976,7 @@ main() {
2050
1976
  init-routines) _dispatch_helper "init-routines-helper.sh" "init-routines-helper.sh" "$@" ;;
2051
1977
  parent-status | ps) _dispatch_helper "parent-status-helper.sh" "parent-status-helper.sh" "$@" ;;
2052
1978
  knowledge) _dispatch_helper "knowledge-helper.sh" "knowledge-helper.sh" "$@" ;;
2053
- campaign | campaigns)
2054
- # P1 provisioning: init/provision/status/ls → campaigns-provision-helper.sh
2055
- # P4 asset binary: asset → campaign-asset-helper.sh
2056
- # P2+P6: all other subcommands → campaign-helper.sh
2057
- local _camp_cmd="${1:-help}"
2058
- local _camp_helper="campaign-helper.sh"
2059
- local _camp_provision_helper="campaigns-provision-helper.sh"
2060
- case "$_camp_cmd" in
2061
- init | provision | ls)
2062
- _dispatch_helper "$_camp_provision_helper" "$_camp_provision_helper" "$@"
2063
- ;;
2064
- status)
2065
- if [[ $# -le 1 || -d "${2:-}" || "${2:-}" == .* || "${2:-}" == /* || "${2:-}" == ~* ]]; then
2066
- _dispatch_helper "$_camp_provision_helper" "$_camp_provision_helper" "$@"
2067
- else
2068
- _dispatch_helper "$_camp_helper" "$_camp_helper" "$@"
2069
- fi
2070
- ;;
2071
- asset | assets)
2072
- shift
2073
- _dispatch_helper "campaign-asset-helper.sh" "campaign-asset-helper.sh" "$@"
2074
- ;;
2075
- grow | growth)
2076
- shift
2077
- local _growth_helper="${AIDEVOPS_CLI_MODULES_DIR%/aidevops-cli}/campaign-growth-helper.py"
2078
- [[ ! -f "$_growth_helper" ]] && _growth_helper="$AGENTS_DIR/scripts/campaign-growth-helper.py"
2079
- if [[ -f "$_growth_helper" ]]; then
2080
- python3 "$_growth_helper" "$@"
2081
- else
2082
- print_error "campaign-growth-helper.py not found. Run: aidevops update"
2083
- return 1
2084
- fi
2085
- ;;
2086
- *)
2087
- _dispatch_helper "$_camp_helper" "$_camp_helper" "$@"
2088
- ;;
2089
- esac
2090
- ;;
1979
+ campaign | campaigns) _main_dispatch_campaign "$@" ;;
2091
1980
  performance) _dispatch_helper "performance-helper.sh" "performance-helper.sh" "$@" ;;
2092
1981
  reach) _dispatch_helper "reach-helper.sh" "reach-helper.sh" "$@" ;;
2093
1982
  config | configure) _dispatch_config "$@" ;;
@@ -2103,4 +1992,84 @@ main() {
2103
1992
  esac
2104
1993
  }
2105
1994
 
1995
+ _main_dispatch_cleanup() {
1996
+ local cleanup_subcommand="${1:-help}"
1997
+ case "$cleanup_subcommand" in
1998
+ branches | remote-branches)
1999
+ shift || true
2000
+ _dispatch_helper "remote-branch-cleanup-helper.sh" "remote-branch-cleanup-helper.sh" "$cleanup_subcommand" "$@"
2001
+ ;;
2002
+ help | --help | -h | "")
2003
+ echo "Usage: aidevops cleanup <branches|remote-branches> [options]"
2004
+ echo ""
2005
+ echo "Cleanup commands:"
2006
+ echo " branches Audit stale remote branches (dry-run default)"
2007
+ echo " remote-branches Alias for branches"
2008
+ echo ""
2009
+ echo "Options:"
2010
+ echo " --repo PATH Repository path (default: current directory)"
2011
+ echo " --remote NAME Remote to audit (default: origin)"
2012
+ echo " --apply Delete safe candidates"
2013
+ echo ""
2014
+ ;;
2015
+ *) print_error "Unknown cleanup subcommand: $cleanup_subcommand (try branches|remote-branches|help)"; return 1 ;;
2016
+ esac
2017
+ return 0
2018
+ }
2019
+
2020
+ _help_vault_and_config_sections() {
2021
+ echo "Vault:"
2022
+ echo " aidevops vault init # Create local encrypted Vault metadata"
2023
+ echo " aidevops vault status # Show uninitialized/locked/unlocked/corrupted"
2024
+ echo " aidevops vault unlock # Unlock into an in-memory local broker"
2025
+ echo " aidevops vault lock # Stop broker and forget in-memory keys"
2026
+ echo " aidevops vault read NAME # Read protected data through broker"
2027
+ echo " aidevops vault update NAME # Encrypt stdin value through broker"
2028
+ echo ""
2029
+ echo "GitHub App Auth:"
2030
+ echo " aidevops github-app-auth status --json # Show active auth mode and budgets"
2031
+ echo " aidevops github-app-auth route issue-list # Explain route decision"
2032
+ echo " aidevops github-app-auth rate-limit --json # Show cached per-pool budgets"
2033
+ echo ""
2034
+ echo "Feature Toggles:"
2035
+ echo " aidevops config list # List all toggles with current values"
2036
+ echo " aidevops config get <key> # Get a toggle value"
2037
+ echo " aidevops config set <k> <v> # Set a toggle (true/false)"
2038
+ echo " aidevops config reset [key] # Reset toggle(s) to defaults"
2039
+ echo " aidevops config path # Show config file path"
2040
+ echo ""
2041
+ return 0
2042
+ }
2043
+
2044
+ _main_dispatch_contributions() {
2045
+ [[ $# -eq 0 ]] && set -- status
2046
+ _dispatch_helper "contribution-watch-helper.sh" "contribution-watch-helper.sh" "$@"
2047
+ return $?
2048
+ }
2049
+
2050
+ _main_dispatch_campaign() {
2051
+ local campaign_command="${1:-help}" campaign_helper="campaign-helper.sh"
2052
+ local provision_helper="campaigns-provision-helper.sh"
2053
+ case "$campaign_command" in
2054
+ init | provision | ls) _dispatch_helper "$provision_helper" "$provision_helper" "$@" ;;
2055
+ status)
2056
+ if [[ $# -le 1 || -d "${2:-}" || "${2:-}" == .* || "${2:-}" == /* || "${2:-}" == ~* ]]; then
2057
+ _dispatch_helper "$provision_helper" "$provision_helper" "$@"
2058
+ else
2059
+ _dispatch_helper "$campaign_helper" "$campaign_helper" "$@"
2060
+ fi
2061
+ ;;
2062
+ asset | assets) shift; _dispatch_helper "campaign-asset-helper.sh" "campaign-asset-helper.sh" "$@" ;;
2063
+ grow | growth)
2064
+ shift
2065
+ local growth_helper="${AIDEVOPS_CLI_MODULES_DIR%/aidevops-cli}/campaign-growth-helper.py"
2066
+ [[ ! -f "$growth_helper" ]] && growth_helper="$AGENTS_DIR/scripts/campaign-growth-helper.py"
2067
+ [[ -f "$growth_helper" ]] || { print_error "campaign-growth-helper.py not found. Run: aidevops update"; return 1; }
2068
+ python3 "$growth_helper" "$@"
2069
+ ;;
2070
+ *) _dispatch_helper "$campaign_helper" "$campaign_helper" "$@" ;;
2071
+ esac
2072
+ return 0
2073
+ }
2074
+
2106
2075
  main "$@"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aidevops",
3
- "version": "3.34.9",
3
+ "version": "3.34.10",
4
4
  "description": "AI DevOps Framework - AI-assisted development workflows, code quality, and deployment automation",
5
5
  "type": "module",
6
6
  "packageManager": "bun@1.3.11",
package/setup.sh CHANGED
@@ -17,7 +17,7 @@ fi
17
17
  # AI Assistant Server Access Framework Setup Script
18
18
  # Helps developers set up the framework for their infrastructure
19
19
  #
20
- # Version: 3.34.9
20
+ # Version: 3.34.10
21
21
  #
22
22
  # Quick Install:
23
23
  # npm install -g aidevops && aidevops update (recommended)