aidevops 3.13.0 → 3.13.2

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.
@@ -51,6 +51,7 @@ setup_git_clis() {
51
51
  echo ""
52
52
  setup_prompt install_git_clis "Install Git CLI tools (${missing_packages[*]}) using $pkg_manager? [Y/n]: " "Y"
53
53
 
54
+ # shellcheck disable=SC2154 # set indirectly by setup_prompt via read
54
55
  if [[ "$install_git_clis" =~ ^[Yy]?$ ]]; then
55
56
  print_info "Installing ${missing_packages[*]}..."
56
57
  if install_packages "$pkg_manager" "${missing_packages[@]}"; then
@@ -233,6 +234,7 @@ setup_file_discovery_tools() {
233
234
  if [[ "$pkg_manager" != "unknown" ]]; then
234
235
  setup_prompt install_fd_tools "Install file discovery tools (${missing_packages[*]}) using $pkg_manager? [Y/n]: " "Y"
235
236
 
237
+ # shellcheck disable=SC2154 # set indirectly by setup_prompt via read
236
238
  if [[ "$install_fd_tools" =~ ^[Yy]?$ ]]; then
237
239
  _install_file_discovery_packages "$pkg_manager" "${missing_packages[@]}"
238
240
  else
@@ -272,6 +274,7 @@ setup_rtk() {
272
274
 
273
275
  setup_prompt install_rtk "Install rtk for token-optimized CLI output? [y/N]: " "n"
274
276
 
277
+ # shellcheck disable=SC2154 # set indirectly by setup_prompt via read
275
278
  if [[ "$install_rtk" =~ ^[Yy]$ ]]; then
276
279
  VERIFIED_INSTALL_SHELL="sh"
277
280
  if command -v brew >/dev/null 2>&1; then
@@ -1922,6 +1925,7 @@ setup_orbstack_vm() {
1922
1925
  fi
1923
1926
 
1924
1927
  setup_prompt install_orb "Install OrbStack? [y/N]: " "n"
1928
+ # shellcheck disable=SC2154 # set indirectly by setup_prompt via read
1925
1929
  if [[ "$install_orb" =~ ^[Yy]$ ]]; then
1926
1930
  if run_with_spinner "Installing OrbStack" brew install --cask orbstack; then
1927
1931
  print_success "OrbStack installed"
@@ -1965,3 +1969,88 @@ setup_ai_orchestration() {
1965
1969
 
1966
1970
  return 0
1967
1971
  }
1972
+
1973
+ # Prompt to install Ollama when the knowledge plane is enabled.
1974
+ # Called from _setup_run_interactive when the user opts in.
1975
+ # Installs Ollama and pulls the recommended fast model (llama3.1:8b).
1976
+ # The reasoning model (llama3.1:70b) and embed model are suggested but not
1977
+ # pulled automatically due to their large size (39 GB and 274 MB respectively).
1978
+ setup_ollama_for_knowledge() {
1979
+ print_info "Ollama — local LLM for knowledge plane (pii/sensitive/privileged tiers)"
1980
+ print_info "Required for: tier:pii, tier:sensitive, tier:privileged routing."
1981
+
1982
+ # Check if Ollama is already installed
1983
+ if command -v ollama >/dev/null 2>&1; then
1984
+ local version
1985
+ version=$(ollama --version 2>/dev/null | grep -o '[0-9][0-9.]*' | head -1) || version="unknown"
1986
+ print_success "Ollama already installed (version: ${version})"
1987
+ else
1988
+ print_info "Ollama not found."
1989
+ if [[ "$(uname -s)" == "Darwin" ]] && command -v brew >/dev/null 2>&1; then
1990
+ print_info "Installing Ollama via Homebrew..."
1991
+ if brew install ollama 2>/dev/null; then
1992
+ print_success "Ollama installed via Homebrew"
1993
+ else
1994
+ print_warning "Homebrew install failed. Download from https://ollama.com"
1995
+ return 0
1996
+ fi
1997
+ else
1998
+ print_info "Install Ollama manually from https://ollama.com"
1999
+ print_info "Then re-run this setup to pull the recommended models."
2000
+ return 0
2001
+ fi
2002
+ fi
2003
+
2004
+ # Deploy the bundle config template
2005
+ local bundle_dir="$HOME/.aidevops/configs"
2006
+ local bundle_dest="${bundle_dir}/ollama-bundle.json"
2007
+ local bundle_src
2008
+ bundle_src="${BASH_SOURCE[0]%/*}/../.agents/templates/ollama-bundle.json"
2009
+ if [[ ! -f "$bundle_src" ]]; then
2010
+ bundle_src="$HOME/.aidevops/agents/templates/ollama-bundle.json"
2011
+ fi
2012
+ if [[ -f "$bundle_src" ]] && [[ ! -f "$bundle_dest" ]]; then
2013
+ mkdir -p "$bundle_dir"
2014
+ cp "$bundle_src" "$bundle_dest"
2015
+ print_success "Ollama bundle config deployed: ${bundle_dest}"
2016
+ fi
2017
+
2018
+ # Start Ollama service if not running
2019
+ if ! curl -sf "http://localhost:11434/api/tags" >/dev/null 2>&1; then
2020
+ print_info "Starting Ollama service..."
2021
+ ollama serve >/dev/null 2>&1 &
2022
+ local i=0
2023
+ while [[ $i -lt 10 ]]; do
2024
+ if curl -sf "http://localhost:11434/api/tags" >/dev/null 2>&1; then
2025
+ break
2026
+ fi
2027
+ sleep 1
2028
+ i=$((i + 1))
2029
+ done
2030
+ fi
2031
+
2032
+ # Pull the fast model (minimum required for pii/sensitive tiers)
2033
+ print_info "Pulling minimum required model: llama3.1:8b (~4.9 GB)"
2034
+ print_info "This is required for tier:pii and tier:sensitive routing."
2035
+ if ollama pull llama3.1:8b 2>/dev/null; then
2036
+ print_success "llama3.1:8b pulled successfully"
2037
+ else
2038
+ print_warning "Failed to pull llama3.1:8b. Run manually: ollama pull llama3.1:8b"
2039
+ fi
2040
+
2041
+ # Pull the embed model (small — pull automatically)
2042
+ print_info "Pulling embed model: nomic-embed-text (~274 MB)"
2043
+ if ollama pull nomic-embed-text 2>/dev/null; then
2044
+ print_success "nomic-embed-text pulled successfully"
2045
+ else
2046
+ print_warning "Failed to pull nomic-embed-text. Run manually: ollama pull nomic-embed-text"
2047
+ fi
2048
+
2049
+ print_info ""
2050
+ print_info "Optional: pull the reasoning model for tier:privileged (~39 GB, requires 48+ GB RAM):"
2051
+ print_info " ollama pull llama3.1:70b"
2052
+ print_info ""
2053
+ print_info "Verify: ollama-helper.sh health"
2054
+
2055
+ return 0
2056
+ }
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.0
15
+ # Version: 3.13.2
16
16
  #
17
17
  # Quick Install:
18
18
  # npm install -g aidevops && aidevops update (recommended)
@@ -142,6 +142,31 @@ _cron_escape() {
142
142
  return 0
143
143
  }
144
144
 
145
+ # GH#21060 / t2911: Per-stage timing helper for non-interactive setup runs.
146
+ # Wraps a function call, records start/end time, and appends one TSV line to
147
+ # $HOME/.aidevops/logs/setup-stage-timings.log:
148
+ # iso8601_utc <TAB> stage_name <TAB> duration_seconds <TAB> exit_code
149
+ # Usage: _time_step "stage_name" function_name [args...]
150
+ # ShellCheck: $@ is used deliberately (SC2068 not applicable; no word-splitting
151
+ # issue since we shift the stage-name arg first and pass the rest as a command).
152
+ _time_step() {
153
+ local _ts_stage="$1"
154
+ shift
155
+ local _ts_start _ts_end _ts_duration _ts_exit
156
+ _ts_start=$(date +%s.%N 2>/dev/null || date +%s)
157
+ _ts_exit=0
158
+ "$@" || _ts_exit=$?
159
+ _ts_end=$(date +%s.%N 2>/dev/null || date +%s)
160
+ _ts_duration=$(awk -v a="$_ts_start" -v b="$_ts_end" 'BEGIN { printf "%.2f", b - a }')
161
+ printf '%s\t%s\t%s\t%s\n' \
162
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
163
+ "$_ts_stage" \
164
+ "$_ts_duration" \
165
+ "$_ts_exit" \
166
+ >>"$HOME/.aidevops/logs/setup-stage-timings.log" 2>/dev/null || true
167
+ return "$_ts_exit"
168
+ }
169
+
145
170
  # Resolve the canonical main worktree path for the current repo.
146
171
  # When setup.sh is run from a linked worktree, launchd/cron should still point
147
172
  # autonomous services at the main repo checkout, not the feature worktree.
@@ -1027,62 +1052,116 @@ setup_knowledge_planes() {
1027
1052
  return 0
1028
1053
  }
1029
1054
 
1055
+ # Provision cases planes for all repos in repos.json where cases != "off".
1056
+ # Idempotent: already-provisioned directories are not modified.
1057
+ # Called from the non-interactive setup path (update) and after interactive init.
1058
+ setup_cases_planes() {
1059
+ local repos_file="$HOME/.config/aidevops/repos.json"
1060
+ local helper
1061
+ helper="${BASH_SOURCE[0]%/*}/.agents/scripts/case-helper.sh"
1062
+ if [[ ! -f "$helper" ]]; then
1063
+ helper="$HOME/.aidevops/agents/scripts/case-helper.sh"
1064
+ fi
1065
+ if [[ ! -f "$helper" ]]; then
1066
+ print_warning "case-helper.sh not found — skipping cases plane provisioning"
1067
+ return 0
1068
+ fi
1069
+ if [[ ! -f "$repos_file" ]]; then
1070
+ return 0
1071
+ fi
1072
+ if ! command -v jq &>/dev/null; then
1073
+ print_warning "jq not installed — skipping cases plane provisioning"
1074
+ return 0
1075
+ fi
1076
+ local repo_path mode
1077
+ while IFS=$'\t' read -r repo_path mode; do
1078
+ [[ -z "$repo_path" || "$mode" == "off" ]] && continue
1079
+ if [[ ! -d "$repo_path" ]]; then
1080
+ print_warning "cases-plane: repo path not found: $repo_path"
1081
+ continue
1082
+ fi
1083
+ bash "$helper" init "$repo_path" || print_warning "cases-plane: init failed for $repo_path"
1084
+ done < <(jq -r '.initialized_repos[] | select(.cases != null and .cases != "off") | [.path, .cases] | @tsv' "$repos_file" 2>/dev/null || true)
1085
+ return 0
1086
+ }
1087
+
1030
1088
  # Non-interactive path: deploy agents and run safe migrations only (no prompts).
1089
+ # GH#21060 / t2911: Every direct function call is wrapped with _time_step so
1090
+ # that a one-line-per-stage TSV timing record is appended to
1091
+ # $HOME/.aidevops/logs/setup-stage-timings.log for post-run diagnostics.
1031
1092
  _setup_run_non_interactive() {
1032
1093
  print_info "Non-interactive mode: deploying agents and running safe migrations only"
1033
- verify_location
1034
- check_requirements
1094
+
1095
+ # GH#21060: Initialise per-stage timing log; rotate if over 10K lines / 1MB.
1096
+ local _stl
1097
+ _stl="$HOME/.aidevops/logs/setup-stage-timings.log"
1098
+ mkdir -p "$(dirname "$_stl")" 2>/dev/null || true
1099
+ if [[ -f "$_stl" ]]; then
1100
+ local _stl_lines _stl_bytes
1101
+ _stl_lines=$(wc -l <"$_stl" 2>/dev/null || echo "0")
1102
+ _stl_bytes=$(wc -c <"$_stl" 2>/dev/null || echo "0")
1103
+ # Strip whitespace that wc adds on some platforms
1104
+ _stl_lines="${_stl_lines//[[:space:]]/}"
1105
+ _stl_bytes="${_stl_bytes//[[:space:]]/}"
1106
+ if [[ "${_stl_lines:-0}" -gt 10000 ]] || [[ "${_stl_bytes:-0}" -gt 1048576 ]]; then
1107
+ : >"$_stl" 2>/dev/null || true
1108
+ print_info "setup-stage-timings.log rotated (was ${_stl_lines} lines / ${_stl_bytes} bytes)"
1109
+ fi
1110
+ fi
1111
+
1112
+ _time_step "verify_location" verify_location
1113
+ _time_step "check_requirements" check_requirements
1035
1114
  # Run quality tool detection in non-interactive mode too (warn-only path).
1036
- check_quality_tools
1115
+ _time_step "check_quality_tools" check_quality_tools
1037
1116
  # Check setsid availability; auto-install util-linux on macOS if missing
1038
1117
  # (GH#21102 / t2926: missing setsid kills workers on every pulse restart).
1039
- setup_setsid_advisory
1040
- check_python_upgrade_available
1041
- set_permissions
1042
- migrate_old_backups
1043
- migrate_loop_state_directories
1044
- migrate_agent_to_agents_folder
1045
- migrate_mcp_env_to_credentials
1046
- migrate_pulse_repos_to_repos_json
1047
- cleanup_deprecated_paths
1048
- migrate_orphaned_supervisor
1049
- backfill_issue_relationships
1050
- cleanup_deprecated_mcps
1051
- cleanup_stale_bun_opencode
1052
- cleanup_stale_health_issue_caches
1053
- cleanup_worktree_entries_in_repos_json
1054
- _cleanup_legacy_model_config
1118
+ _time_step "setup_setsid_advisory" setup_setsid_advisory
1119
+ _time_step "check_python_upgrade_available" check_python_upgrade_available
1120
+ _time_step "set_permissions" set_permissions
1121
+ _time_step "migrate_old_backups" migrate_old_backups
1122
+ _time_step "migrate_loop_state_directories" migrate_loop_state_directories
1123
+ _time_step "migrate_agent_to_agents_folder" migrate_agent_to_agents_folder
1124
+ _time_step "migrate_mcp_env_to_credentials" migrate_mcp_env_to_credentials
1125
+ _time_step "migrate_pulse_repos_to_repos_json" migrate_pulse_repos_to_repos_json
1126
+ _time_step "cleanup_deprecated_paths" cleanup_deprecated_paths
1127
+ _time_step "migrate_orphaned_supervisor" migrate_orphaned_supervisor
1128
+ _time_step "backfill_issue_relationships" backfill_issue_relationships
1129
+ _time_step "cleanup_deprecated_mcps" cleanup_deprecated_mcps
1130
+ _time_step "cleanup_stale_bun_opencode" cleanup_stale_bun_opencode
1131
+ _time_step "cleanup_stale_health_issue_caches" cleanup_stale_health_issue_caches
1132
+ _time_step "cleanup_worktree_entries_in_repos_json" cleanup_worktree_entries_in_repos_json
1133
+ _time_step "_cleanup_legacy_model_config" _cleanup_legacy_model_config
1055
1134
  # t2888: install/heal opencode-ai. Companion to t2887's runtime canary
1056
1135
  # fail-fast -- t2887 detects when $OPENCODE_BIN_DEFAULT is wrong, this
1057
1136
  # one fixes it by reinstalling opencode-ai@latest (overwriting any bin
1058
1137
  # collision with @anthropic-ai/claude-code or similar). Skipping this
1059
1138
  # in non-interactive mode is the bug PR #20189 introduced and what
1060
1139
  # alex-solovyev's runner spam stemmed from.
1061
- setup_opencode_cli
1062
- validate_opencode_config
1063
- deploy_aidevops_agents
1064
- _setup_install_pulse_plist_early
1065
- _deploy_hotfix_config
1066
- sync_agent_sources
1067
- install_aidevops_cli
1068
- setup_shellcheck_wrapper
1140
+ _time_step "setup_opencode_cli" setup_opencode_cli
1141
+ _time_step "validate_opencode_config" validate_opencode_config
1142
+ _time_step "deploy_aidevops_agents" deploy_aidevops_agents
1143
+ _time_step "_setup_install_pulse_plist_early" _setup_install_pulse_plist_early
1144
+ _time_step "_deploy_hotfix_config" _deploy_hotfix_config
1145
+ _time_step "sync_agent_sources" sync_agent_sources
1146
+ _time_step "install_aidevops_cli" install_aidevops_cli
1147
+ _time_step "setup_shellcheck_wrapper" setup_shellcheck_wrapper
1069
1148
  if is_feature_enabled safety_hooks 2>/dev/null; then
1070
- setup_safety_hooks
1149
+ _time_step "setup_safety_hooks" setup_safety_hooks
1071
1150
  fi
1072
- init_settings_json
1151
+ _time_step "init_settings_json" init_settings_json
1073
1152
 
1074
1153
  # Parallelise independent skill operations (t1356: ~84s serial -> ~18s parallel)
1075
1154
  # generate_agent_skills must complete before create_skill_symlinks (symlinks
1076
1155
  # depend on generated SKILL.md files). scan_imported_skills is independent.
1077
1156
  local _pid_symlinks=""
1078
- if generate_agent_skills; then
1079
- create_skill_symlinks &
1157
+ if _time_step "generate_agent_skills" generate_agent_skills; then
1158
+ _time_step "create_skill_symlinks" create_skill_symlinks &
1080
1159
  _pid_symlinks=$!
1081
1160
  else
1082
1161
  print_warning "Agent skills generation failed — skipping skill symlinks"
1083
1162
  fi
1084
1163
 
1085
- scan_imported_skills &
1164
+ _time_step "scan_imported_skills" scan_imported_skills &
1086
1165
  local _pid_scan=$!
1087
1166
 
1088
1167
  if [[ -n "$_pid_symlinks" ]]; then
@@ -1090,42 +1169,44 @@ _setup_run_non_interactive() {
1090
1169
  fi
1091
1170
  wait "$_pid_scan" 2>/dev/null || print_warning "Skill security scan encountered issues (non-critical)"
1092
1171
 
1093
- inject_agents_reference
1094
- deploy_agents_to_runtimes
1095
- update_opencode_config
1096
- update_claude_config
1097
- update_codex_config
1098
- update_cursor_config
1099
- disable_ondemand_mcps
1172
+ _time_step "inject_agents_reference" inject_agents_reference
1173
+ _time_step "deploy_agents_to_runtimes" deploy_agents_to_runtimes
1174
+ _time_step "update_opencode_config" update_opencode_config
1175
+ _time_step "update_claude_config" update_claude_config
1176
+ _time_step "update_codex_config" update_codex_config
1177
+ _time_step "update_cursor_config" update_cursor_config
1178
+ _time_step "disable_ondemand_mcps" disable_ondemand_mcps
1100
1179
  # Scaffold personal routines repo if not already present (idempotent).
1101
1180
  # Creates local git repo + private GitHub remote for personal repo only.
1102
1181
  # Org repos require explicit: aidevops init-routines --org <name>
1103
- setup_routines
1182
+ _time_step "setup_routines" setup_routines
1104
1183
  # Install/refresh the privacy-guard pre-push hook in every initialized
1105
1184
  # repo so TODO/todo/README/ISSUE_TEMPLATE pushes to public GitHub repos
1106
1185
  # are scanned for private slug leaks (t1968).
1107
- setup_privacy_guard
1186
+ _time_step "setup_privacy_guard" setup_privacy_guard
1108
1187
  # Install/refresh the complexity-regression pre-push hook in every
1109
1188
  # initialized repo so pushes that introduce new function-complexity,
1110
1189
  # nesting-depth, or file-size violations are caught before CI (t2198).
1111
- setup_complexity_guard
1190
+ _time_step "setup_complexity_guard" setup_complexity_guard
1112
1191
  # Install/refresh the canonical-on-main post-checkout hook in every
1113
1192
  # initialized repo so branch switches away from main in the canonical
1114
1193
  # directory are warned against (t1995). Complements pre-edit-check.sh's
1115
1194
  # t1990 edit-time check by catching the branch switch itself.
1116
- setup_canonical_guard
1195
+ _time_step "setup_canonical_guard" setup_canonical_guard
1117
1196
  # Install/refresh the task-id collision guard commit-msg hook in every
1118
1197
  # initialized repo so invented t-IDs in commit subjects are rejected
1119
1198
  # at commit time (t2047). Belt-and-braces with the CI check in
1120
- # .github/workflows/ta[redacted-credential].yml.
1121
- setup_task_id_guard
1199
+ # .github/workflows/task-id-collision-check.yml.
1200
+ _time_step "setup_task_id_guard" setup_task_id_guard
1122
1201
  # Apply Spotlight + Time Machine exclusions to every worktree across
1123
1202
  # registered repos so the backup/index cascade triggered by node_modules
1124
1203
  # copies doesn't burn CPU (t2885). Idempotent. macOS only — Linux
1125
1204
  # indexers tracked separately.
1126
- setup_worktree_exclusions
1205
+ _time_step "setup_worktree_exclusions" setup_worktree_exclusions
1127
1206
  # Provision knowledge planes for repos where knowledge != "off" (idempotent).
1128
- setup_knowledge_planes
1207
+ _time_step "setup_knowledge_planes" setup_knowledge_planes
1208
+ # Provision cases planes for repos where cases != "off" (idempotent).
1209
+ _time_step "setup_cases_planes" setup_cases_planes
1129
1210
  return 0
1130
1211
  }
1131
1212
 
@@ -1210,6 +1291,7 @@ _setup_run_interactive() {
1210
1291
  confirm_step "Setup QuickFile MCP (UK accounting)" && setup_quickfile_mcp
1211
1292
  confirm_step "Setup browser automation tools" && setup_browser_tools
1212
1293
  confirm_step "Setup AI orchestration frameworks info" && setup_ai_orchestration
1294
+ confirm_step "Setup Ollama (local LLM for knowledge plane pii/sensitive/privileged tiers)" && setup_ollama_for_knowledge
1213
1295
  confirm_step "Setup Google Workspace CLI (Gmail, Calendar, Drive)" && setup_google_workspace_cli
1214
1296
  confirm_step "Setup OpenCode CLI (AI coding tool)" && setup_opencode_cli
1215
1297
  confirm_step "Setup OpenCode plugins" && setup_opencode_plugins
@@ -1350,6 +1432,7 @@ _setup_post_setup_steps() {
1350
1432
  setup_contribution_watch
1351
1433
  setup_complexity_scan
1352
1434
  setup_pulse_merge_routine
1435
+ setup_peer_productivity_monitor
1353
1436
  setup_draft_responses
1354
1437
  setup_profile_readme
1355
1438
  setup_oauth_token_refresh