aidevops 3.1.135 → 3.1.137

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.1.135
1
+ 3.1.137
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.1.135
6
+ # Version: 3.1.137
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.1.135",
3
+ "version": "3.1.137",
4
4
  "description": "AI DevOps Framework - AI-assisted development workflows, code quality, and deployment automation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -60,6 +60,193 @@ check_opencode_prompt_drift() {
60
60
  return 0
61
61
  }
62
62
 
63
+ # _deploy_agents_clean_mode target_dir [preserved_dirs...]
64
+ # Removes stale files from target_dir while preserving listed subdirectories.
65
+ _deploy_agents_clean_mode() {
66
+ local target_dir="$1"
67
+ shift
68
+ local -a preserved_dirs=("$@")
69
+
70
+ print_info "Clean mode: removing stale files from $target_dir (preserving ${preserved_dirs[*]})"
71
+ local tmp_preserve
72
+ tmp_preserve="$(mktemp -d)"
73
+ trap 'rm -rf "${tmp_preserve:-}"' RETURN
74
+ if [[ -z "$tmp_preserve" || ! -d "$tmp_preserve" ]]; then
75
+ print_error "Failed to create temp dir for preserving agents"
76
+ return 1
77
+ fi
78
+ local preserve_failed=false
79
+ for pdir in "${preserved_dirs[@]}"; do
80
+ if [[ -d "$target_dir/$pdir" ]]; then
81
+ if ! cp -R "$target_dir/$pdir" "$tmp_preserve/$pdir"; then
82
+ preserve_failed=true
83
+ fi
84
+ fi
85
+ done
86
+ if [[ "$preserve_failed" == "true" ]]; then
87
+ print_error "Failed to preserve user/plugin agents; aborting clean"
88
+ rm -rf "$tmp_preserve"
89
+ return 1
90
+ fi
91
+ rm -rf "${target_dir:?}"/*
92
+ for pdir in "${preserved_dirs[@]}"; do
93
+ if [[ -d "$tmp_preserve/$pdir" ]]; then
94
+ cp -R "$tmp_preserve/$pdir" "$target_dir/$pdir"
95
+ fi
96
+ done
97
+ rm -rf "$tmp_preserve"
98
+ return 0
99
+ }
100
+
101
+ # _deploy_agents_copy source_dir target_dir [plugin_namespaces...]
102
+ # Copies agent files using rsync (preferred) or tar fallback.
103
+ # Returns 0 on success, 1 on failure.
104
+ _deploy_agents_copy() {
105
+ local source_dir="$1"
106
+ local target_dir="$2"
107
+ shift 2
108
+ local -a plugin_namespaces=("$@")
109
+
110
+ local deploy_ok=false
111
+ if command -v rsync &>/dev/null; then
112
+ local -a rsync_excludes=("--exclude=loop-state/" "--exclude=custom/" "--exclude=draft/")
113
+ for pns in "${plugin_namespaces[@]}"; do
114
+ rsync_excludes+=("--exclude=${pns}/")
115
+ done
116
+ if rsync -a "${rsync_excludes[@]}" "$source_dir/" "$target_dir/"; then
117
+ deploy_ok=true
118
+ fi
119
+ else
120
+ # Fallback: use tar with exclusions to match rsync behavior
121
+ local -a tar_excludes=("--exclude=loop-state" "--exclude=custom" "--exclude=draft")
122
+ for pns in "${plugin_namespaces[@]}"; do
123
+ tar_excludes+=("--exclude=$pns")
124
+ done
125
+ if (cd "$source_dir" && tar cf - "${tar_excludes[@]}" .) | (cd "$target_dir" && tar xf -); then
126
+ deploy_ok=true
127
+ fi
128
+ fi
129
+
130
+ if [[ "$deploy_ok" == "true" ]]; then
131
+ return 0
132
+ fi
133
+ return 1
134
+ }
135
+
136
+ # _inject_plan_reminder target_dir
137
+ # Injects the extracted OpenCode plan-reminder into Plan+ if the placeholder is present.
138
+ _inject_plan_reminder() {
139
+ local target_dir="$1"
140
+ local plan_reminder="$HOME/.aidevops/cache/opencode-prompts/plan-reminder.txt"
141
+ local plan_plus="$target_dir/plan-plus.md"
142
+ if [[ ! -f "$plan_reminder" || ! -f "$plan_plus" ]]; then
143
+ return 0
144
+ fi
145
+ if ! grep -q "OPENCODE-PLAN-REMINDER-INJECT" "$plan_plus"; then
146
+ return 0
147
+ fi
148
+ local tmp_file in_placeholder
149
+ tmp_file=$(mktemp)
150
+ trap 'rm -f "${tmp_file:-}"' RETURN
151
+ in_placeholder=false
152
+ while IFS= read -r line || [[ -n "$line" ]]; do
153
+ if [[ "$line" == *"OPENCODE-PLAN-REMINDER-INJECT-START"* ]]; then
154
+ echo "$line" >>"$tmp_file"
155
+ cat "$plan_reminder" >>"$tmp_file"
156
+ in_placeholder=true
157
+ elif [[ "$line" == *"OPENCODE-PLAN-REMINDER-INJECT-END"* ]]; then
158
+ echo "$line" >>"$tmp_file"
159
+ in_placeholder=false
160
+ elif [[ "$in_placeholder" == false ]]; then
161
+ echo "$line" >>"$tmp_file"
162
+ fi
163
+ done <"$plan_plus"
164
+ mv "$tmp_file" "$plan_plus"
165
+ print_info "Injected OpenCode plan-reminder into Plan+"
166
+ return 0
167
+ }
168
+
169
+ # _deploy_agents_post_copy target_dir repo_dir source_dir plugins_file
170
+ # Runs all post-copy steps: permissions, VERSION, advisories, plan-reminder,
171
+ # mailbox migration, stale-file migration, and plugin deployment.
172
+ _deploy_agents_post_copy() {
173
+ local target_dir="$1"
174
+ local repo_dir="$2"
175
+ local source_dir="$3"
176
+ local plugins_file="$4"
177
+
178
+ # Set permissions on scripts (top-level and modularised subdirectories)
179
+ chmod +x "$target_dir/scripts/"*.sh 2>/dev/null || true
180
+ find "$target_dir/scripts" -mindepth 2 -name "*.sh" -exec chmod +x {} + 2>/dev/null || true
181
+
182
+ # Count what was deployed
183
+ local agent_count script_count
184
+ agent_count=$(find "$target_dir" -name "*.md" -type f | wc -l | tr -d ' ')
185
+ script_count=$(find "$target_dir/scripts" -name "*.sh" -type f 2>/dev/null | wc -l | tr -d ' ')
186
+ print_info "Deployed $agent_count agent files and $script_count scripts"
187
+
188
+ # Symlink OpenCode's node_modules into the plugin directory (t1551)
189
+ local oc_node_modules="$HOME/.config/opencode/node_modules"
190
+ local plugin_dir="$target_dir/plugins/opencode-aidevops"
191
+ if [[ -d "$oc_node_modules" && -d "$plugin_dir" ]]; then
192
+ ln -sf "$oc_node_modules" "$plugin_dir/node_modules" 2>/dev/null || true
193
+ fi
194
+
195
+ # Copy VERSION file from repo root to deployed agents
196
+ if [[ -f "$repo_dir/VERSION" ]]; then
197
+ if cp "$repo_dir/VERSION" "$target_dir/VERSION"; then
198
+ print_info "Copied VERSION file to deployed agents"
199
+ else
200
+ print_warning "Failed to copy VERSION file (Plan+ may not read version correctly)"
201
+ fi
202
+ else
203
+ print_warning "VERSION file not found in repo root"
204
+ fi
205
+
206
+ # Deploy security advisories (shown in session greeting until dismissed)
207
+ local advisories_source="$source_dir/advisories"
208
+ local advisories_target="$HOME/.aidevops/advisories"
209
+ if [[ -d "$advisories_source" ]]; then
210
+ mkdir -p "$advisories_target"
211
+ local adv_count=0
212
+ for adv_file in "$advisories_source"/*.advisory; do
213
+ [[ -f "$adv_file" ]] || continue
214
+ cp "$adv_file" "$advisories_target/"
215
+ adv_count=$((adv_count + 1))
216
+ done
217
+ if [[ "$adv_count" -gt 0 ]]; then
218
+ print_info "Deployed $adv_count security advisory/advisories"
219
+ fi
220
+ fi
221
+
222
+ # Inject extracted OpenCode plan-reminder into Plan+ if available
223
+ _inject_plan_reminder "$target_dir"
224
+
225
+ # Migrate mailbox from TOON files to SQLite (if old files exist)
226
+ local aidevops_workspace_dir="${AIDEVOPS_WORKSPACE_DIR:-$HOME/.aidevops/.agent-workspace}"
227
+ local mail_dir="${AIDEVOPS_MAIL_DIR:-${aidevops_workspace_dir}/mail}"
228
+ local mail_script="$target_dir/scripts/mail-helper.sh"
229
+ if [[ -x "$mail_script" ]] && find "$mail_dir" -name "*.toon" 2>/dev/null | grep -q .; then
230
+ if "$mail_script" migrate; then
231
+ print_success "Mailbox migration complete"
232
+ else
233
+ print_warning "Mailbox migration had issues (non-critical, old files preserved)"
234
+ fi
235
+ fi
236
+
237
+ # Migration: wavespeed.md moved from services/ai-generation/ to tools/video/ (v2.111+)
238
+ local old_wavespeed="$target_dir/services/ai-generation/wavespeed.md"
239
+ if [[ -f "$old_wavespeed" ]]; then
240
+ rm -f "$old_wavespeed"
241
+ rmdir "$target_dir/services/ai-generation" 2>/dev/null || true
242
+ print_info "Migrated wavespeed.md from services/ai-generation/ to tools/video/"
243
+ fi
244
+
245
+ # Deploy enabled plugins from plugins.json
246
+ deploy_plugins "$target_dir" "$plugins_file"
247
+ return 0
248
+ }
249
+
63
250
  deploy_aidevops_agents() {
64
251
  print_info "Deploying aidevops agents to ~/.aidevops/agents/..."
65
252
 
@@ -84,8 +271,7 @@ deploy_aidevops_agents() {
84
271
  # Collect plugin namespace directories to preserve during deployment
85
272
  local -a plugin_namespaces=()
86
273
  if [[ -f "$plugins_file" ]] && command -v jq &>/dev/null; then
87
- local ns
88
- local safe_ns
274
+ local ns safe_ns
89
275
  while IFS= read -r ns; do
90
276
  if [[ -n "$ns" ]] && safe_ns=$(sanitize_plugin_namespace "$ns" 2>/dev/null); then
91
277
  plugin_namespaces+=("$safe_ns")
@@ -98,47 +284,16 @@ deploy_aidevops_agents() {
98
284
  create_backup_with_rotation "$target_dir" "agents"
99
285
  fi
100
286
 
101
- # Create target directory and copy agents
287
+ # Create target directory
102
288
  mkdir -p "$target_dir"
103
289
 
104
290
  # If clean mode, remove stale files first (preserving user and plugin directories)
105
291
  if [[ "$CLEAN_MODE" == "true" ]]; then
106
- # Build list of directories to preserve: custom, draft, plus plugin namespaces
107
292
  local -a preserved_dirs=("custom" "draft")
108
- if [[ ${#plugin_namespaces[@]} -gt 0 ]]; then
109
- for pns in "${plugin_namespaces[@]}"; do
110
- preserved_dirs+=("$pns")
111
- done
112
- fi
113
- print_info "Clean mode: removing stale files from $target_dir (preserving ${preserved_dirs[*]})"
114
- local tmp_preserve
115
- tmp_preserve="$(mktemp -d)"
116
- trap 'rm -rf "${tmp_preserve:-}"' RETURN
117
- if [[ -z "$tmp_preserve" || ! -d "$tmp_preserve" ]]; then
118
- print_error "Failed to create temp dir for preserving agents"
119
- return 1
120
- fi
121
- local preserve_failed=false
122
- for pdir in "${preserved_dirs[@]}"; do
123
- if [[ -d "$target_dir/$pdir" ]]; then
124
- if ! cp -R "$target_dir/$pdir" "$tmp_preserve/$pdir"; then
125
- preserve_failed=true
126
- fi
127
- fi
293
+ for pns in "${plugin_namespaces[@]}"; do
294
+ preserved_dirs+=("$pns")
128
295
  done
129
- if [[ "$preserve_failed" == "true" ]]; then
130
- print_error "Failed to preserve user/plugin agents; aborting clean"
131
- rm -rf "$tmp_preserve"
132
- return 1
133
- fi
134
- rm -rf "${target_dir:?}"/*
135
- # Restore preserved directories
136
- for pdir in "${preserved_dirs[@]}"; do
137
- if [[ -d "$tmp_preserve/$pdir" ]]; then
138
- cp -R "$tmp_preserve/$pdir" "$target_dir/$pdir"
139
- fi
140
- done
141
- rm -rf "$tmp_preserve"
296
+ _deploy_agents_clean_mode "$target_dir" "${preserved_dirs[@]}" || return 1
142
297
  fi
143
298
 
144
299
  # Copy all agent files and folders, excluding:
@@ -146,133 +301,9 @@ deploy_aidevops_agents() {
146
301
  # - custom/ (user's private agents, never overwritten)
147
302
  # - draft/ (user's experimental agents, never overwritten)
148
303
  # - plugin namespace directories (managed separately)
149
- # Use rsync for selective exclusion
150
- local deploy_ok=false
151
- if command -v rsync &>/dev/null; then
152
- local -a rsync_excludes=("--exclude=loop-state/" "--exclude=custom/" "--exclude=draft/")
153
- if [[ ${#plugin_namespaces[@]} -gt 0 ]]; then
154
- for pns in "${plugin_namespaces[@]}"; do
155
- rsync_excludes+=("--exclude=${pns}/")
156
- done
157
- fi
158
- if rsync -a "${rsync_excludes[@]}" "$source_dir/" "$target_dir/"; then
159
- deploy_ok=true
160
- fi
161
- else
162
- # Fallback: use tar with exclusions to match rsync behavior
163
- local -a tar_excludes=("--exclude=loop-state" "--exclude=custom" "--exclude=draft")
164
- if [[ ${#plugin_namespaces[@]} -gt 0 ]]; then
165
- for pns in "${plugin_namespaces[@]}"; do
166
- tar_excludes+=("--exclude=$pns")
167
- done
168
- fi
169
- if (cd "$source_dir" && tar cf - "${tar_excludes[@]}" .) | (cd "$target_dir" && tar xf -); then
170
- deploy_ok=true
171
- fi
172
- fi
173
-
174
- if [[ "$deploy_ok" == "true" ]]; then
304
+ if _deploy_agents_copy "$source_dir" "$target_dir" "${plugin_namespaces[@]}"; then
175
305
  print_success "Deployed agents to $target_dir"
176
-
177
- # Set permissions on scripts (top-level and modularised subdirectories)
178
- chmod +x "$target_dir/scripts/"*.sh 2>/dev/null || true
179
- find "$target_dir/scripts" -mindepth 2 -name "*.sh" -exec chmod +x {} + 2>/dev/null || true
180
-
181
- # Count what was deployed
182
- local agent_count
183
- agent_count=$(find "$target_dir" -name "*.md" -type f | wc -l | tr -d ' ')
184
- local script_count
185
- script_count=$(find "$target_dir/scripts" -name "*.sh" -type f 2>/dev/null | wc -l | tr -d ' ')
186
-
187
- print_info "Deployed $agent_count agent files and $script_count scripts"
188
-
189
- # Symlink OpenCode's node_modules into the plugin directory (t1551)
190
- # The cursor proxy vendored files import @bufbuild/protobuf and zod,
191
- # which are installed in OpenCode's config node_modules but not
192
- # resolvable from the deployed plugin path (~/.aidevops/agents/).
193
- local oc_node_modules="$HOME/.config/opencode/node_modules"
194
- local plugin_dir="$target_dir/plugins/opencode-aidevops"
195
- if [[ -d "$oc_node_modules" && -d "$plugin_dir" ]]; then
196
- ln -sf "$oc_node_modules" "$plugin_dir/node_modules" 2>/dev/null || true
197
- fi
198
-
199
- # Copy VERSION file from repo root to deployed agents
200
- if [[ -f "$repo_dir/VERSION" ]]; then
201
- if cp "$repo_dir/VERSION" "$target_dir/VERSION"; then
202
- print_info "Copied VERSION file to deployed agents"
203
- else
204
- print_warning "Failed to copy VERSION file (Plan+ may not read version correctly)"
205
- fi
206
- else
207
- print_warning "VERSION file not found in repo root"
208
- fi
209
-
210
- # Deploy security advisories (shown in session greeting until dismissed)
211
- local advisories_source="$source_dir/advisories"
212
- local advisories_target="$HOME/.aidevops/advisories"
213
- if [[ -d "$advisories_source" ]]; then
214
- mkdir -p "$advisories_target"
215
- local adv_count=0
216
- for adv_file in "$advisories_source"/*.advisory; do
217
- [[ -f "$adv_file" ]] || continue
218
- cp "$adv_file" "$advisories_target/"
219
- adv_count=$((adv_count + 1))
220
- done
221
- if [[ "$adv_count" -gt 0 ]]; then
222
- print_info "Deployed $adv_count security advisory/advisories"
223
- fi
224
- fi
225
-
226
- # Inject extracted OpenCode plan-reminder into Plan+ if available
227
- local plan_reminder="$HOME/.aidevops/cache/opencode-prompts/plan-reminder.txt"
228
- local plan_plus="$target_dir/plan-plus.md"
229
- if [[ -f "$plan_reminder" && -f "$plan_plus" ]]; then
230
- # Check if plan-plus.md has the placeholder marker
231
- if grep -q "OPENCODE-PLAN-REMINDER-INJECT" "$plan_plus"; then
232
- # Replace placeholder with extracted content using sed
233
- # (awk -v doesn't handle multi-line content with special chars well)
234
- local tmp_file
235
- tmp_file=$(mktemp)
236
- trap 'rm -f "${tmp_file:-}"' RETURN
237
- local in_placeholder=false
238
- while IFS= read -r line || [[ -n "$line" ]]; do
239
- if [[ "$line" == *"OPENCODE-PLAN-REMINDER-INJECT-START"* ]]; then
240
- echo "$line" >>"$tmp_file"
241
- cat "$plan_reminder" >>"$tmp_file"
242
- in_placeholder=true
243
- elif [[ "$line" == *"OPENCODE-PLAN-REMINDER-INJECT-END"* ]]; then
244
- echo "$line" >>"$tmp_file"
245
- in_placeholder=false
246
- elif [[ "$in_placeholder" == false ]]; then
247
- echo "$line" >>"$tmp_file"
248
- fi
249
- done <"$plan_plus"
250
- mv "$tmp_file" "$plan_plus"
251
- print_info "Injected OpenCode plan-reminder into Plan+"
252
- fi
253
- fi
254
- # Migrate mailbox from TOON files to SQLite (if old files exist)
255
- local aidevops_workspace_dir="${AIDEVOPS_WORKSPACE_DIR:-$HOME/.aidevops/.agent-workspace}"
256
- local mail_dir="${AIDEVOPS_MAIL_DIR:-${aidevops_workspace_dir}/mail}"
257
- local mail_script="$target_dir/scripts/mail-helper.sh"
258
- if [[ -x "$mail_script" ]] && find "$mail_dir" -name "*.toon" 2>/dev/null | grep -q .; then
259
- if "$mail_script" migrate; then
260
- print_success "Mailbox migration complete"
261
- else
262
- print_warning "Mailbox migration had issues (non-critical, old files preserved)"
263
- fi
264
- fi
265
-
266
- # Migration: wavespeed.md moved from services/ai-generation/ to tools/video/ (v2.111+)
267
- local old_wavespeed="$target_dir/services/ai-generation/wavespeed.md"
268
- if [[ -f "$old_wavespeed" ]]; then
269
- rm -f "$old_wavespeed"
270
- rmdir "$target_dir/services/ai-generation" 2>/dev/null || true
271
- print_info "Migrated wavespeed.md from services/ai-generation/ to tools/video/"
272
- fi
273
-
274
- # Deploy enabled plugins from plugins.json
275
- deploy_plugins "$target_dir" "$plugins_file"
306
+ _deploy_agents_post_copy "$target_dir" "$repo_dir" "$source_dir" "$plugins_file"
276
307
  else
277
308
  print_error "Failed to deploy agents"
278
309
  return 1
@@ -522,6 +553,97 @@ setup_beads() {
522
553
  return 0
523
554
  }
524
555
 
556
+ # _install_bv_tool: install the bv (beads_viewer) TUI tool.
557
+ # Returns 0 if installed, 1 if skipped or failed.
558
+ _install_bv_tool() {
559
+ read -r -p " Install bv (TUI with PageRank, critical path, graph analytics)? [Y/n]: " install_viewer
560
+ if [[ ! "$install_viewer" =~ ^[Yy]?$ ]]; then
561
+ print_info "Install later:"
562
+ print_info " Homebrew: brew tap dicklesworthstone/tap && brew install dicklesworthstone/tap/bv"
563
+ print_info " Go: go install github.com/Dicklesworthstone/beads_viewer/cmd/bv@latest"
564
+ return 1
565
+ fi
566
+ if command -v brew &>/dev/null; then
567
+ if run_with_spinner "Installing bv via Homebrew" brew install dicklesworthstone/tap/bv; then
568
+ print_info "Run: bv (in a beads-enabled project)"
569
+ return 0
570
+ else
571
+ print_warning "Homebrew install failed - try manually:"
572
+ print_info " brew install dicklesworthstone/tap/bv"
573
+ return 1
574
+ fi
575
+ elif command -v go &>/dev/null; then
576
+ if run_with_spinner "Installing bv via Go" go install github.com/Dicklesworthstone/beads_viewer/cmd/bv@latest; then
577
+ print_info "Run: bv (in a beads-enabled project)"
578
+ return 0
579
+ else
580
+ print_warning "Go install failed"
581
+ return 1
582
+ fi
583
+ else
584
+ # Offer verified install script (download-then-execute, not piped)
585
+ read -r -p " Install bv via install script? [Y/n]: " use_script
586
+ if [[ "$use_script" =~ ^[Yy]?$ ]]; then
587
+ if verified_install "bv (beads viewer)" "https://raw.githubusercontent.com/Dicklesworthstone/beads_viewer/main/install.sh"; then
588
+ print_info "Run: bv (in a beads-enabled project)"
589
+ return 0
590
+ else
591
+ print_warning "Install script failed - try manually:"
592
+ print_info " Homebrew: brew tap dicklesworthstone/tap && brew install dicklesworthstone/tap/bv"
593
+ return 1
594
+ fi
595
+ else
596
+ print_info "Install later:"
597
+ print_info " Homebrew: brew tap dicklesworthstone/tap && brew install dicklesworthstone/tap/bv"
598
+ print_info " Go: go install github.com/Dicklesworthstone/beads_viewer/cmd/bv@latest"
599
+ return 1
600
+ fi
601
+ fi
602
+ }
603
+
604
+ # _install_beads_node_tools: install beads-ui and bdui via npm.
605
+ # Echoes the count of tools installed to stdout.
606
+ _install_beads_node_tools() {
607
+ local count=0
608
+ if ! command -v npm &>/dev/null; then
609
+ echo "$count"
610
+ return 0
611
+ fi
612
+ read -r -p " Install beads-ui (Web dashboard)? [Y/n]: " install_web
613
+ if [[ "$install_web" =~ ^[Yy]?$ ]]; then
614
+ if run_with_spinner "Installing beads-ui" npm_global_install beads-ui; then
615
+ print_info "Run: beads-ui"
616
+ count=$((count + 1))
617
+ fi
618
+ fi
619
+ read -r -p " Install bdui (React/Ink TUI)? [Y/n]: " install_bdui
620
+ if [[ "$install_bdui" =~ ^[Yy]?$ ]]; then
621
+ if run_with_spinner "Installing bdui" npm_global_install bdui; then
622
+ print_info "Run: bdui"
623
+ count=$((count + 1))
624
+ fi
625
+ fi
626
+ echo "$count"
627
+ return 0
628
+ }
629
+
630
+ # _install_perles: install the perles BQL query language TUI via cargo.
631
+ # Returns 0 if installed, 1 if skipped or unavailable.
632
+ _install_perles() {
633
+ if ! command -v cargo &>/dev/null; then
634
+ return 1
635
+ fi
636
+ read -r -p " Install perles (BQL query language TUI)? [Y/n]: " install_perles
637
+ if [[ ! "$install_perles" =~ ^[Yy]?$ ]]; then
638
+ return 1
639
+ fi
640
+ if run_with_spinner "Installing perles (Rust compile)" cargo install perles; then
641
+ print_info "Run: perles"
642
+ return 0
643
+ fi
644
+ return 1
645
+ }
646
+
525
647
  setup_beads_ui() {
526
648
  echo ""
527
649
  print_info "Beads UI tools provide enhanced visualization:"
@@ -542,76 +664,18 @@ setup_beads_ui() {
542
664
 
543
665
  # bv (beads_viewer) - Go TUI installed via Homebrew
544
666
  # https://github.com/Dicklesworthstone/beads_viewer
545
- read -r -p " Install bv (TUI with PageRank, critical path, graph analytics)? [Y/n]: " install_viewer
546
- if [[ "$install_viewer" =~ ^[Yy]?$ ]]; then
547
- if command -v brew &>/dev/null; then
548
- # brew install user/tap/formula auto-taps
549
- if run_with_spinner "Installing bv via Homebrew" brew install dicklesworthstone/tap/bv; then
550
- print_info "Run: bv (in a beads-enabled project)"
551
- ((++installed_count))
552
- else
553
- print_warning "Homebrew install failed - try manually:"
554
- print_info " brew install dicklesworthstone/tap/bv"
555
- fi
556
- else
557
- # No Homebrew - try install script or Go
558
- print_warning "Homebrew not found"
559
- if command -v go &>/dev/null; then
560
- # Go available - use go install
561
- if run_with_spinner "Installing bv via Go" go install github.com/Dicklesworthstone/beads_viewer/cmd/bv@latest; then
562
- print_info "Run: bv (in a beads-enabled project)"
563
- ((++installed_count))
564
- else
565
- print_warning "Go install failed"
566
- fi
567
- else
568
- # Offer verified install script (download-then-execute, not piped)
569
- read -r -p " Install bv via install script? [Y/n]: " use_script
570
- if [[ "$use_script" =~ ^[Yy]?$ ]]; then
571
- if verified_install "bv (beads viewer)" "https://raw.githubusercontent.com/Dicklesworthstone/beads_viewer/main/install.sh"; then
572
- print_info "Run: bv (in a beads-enabled project)"
573
- ((++installed_count))
574
- else
575
- print_warning "Install script failed - try manually:"
576
- print_info " Homebrew: brew tap dicklesworthstone/tap && brew install dicklesworthstone/tap/bv"
577
- fi
578
- else
579
- print_info "Install later:"
580
- print_info " Homebrew: brew tap dicklesworthstone/tap && brew install dicklesworthstone/tap/bv"
581
- print_info " Go: go install github.com/Dicklesworthstone/beads_viewer/cmd/bv@latest"
582
- fi
583
- fi
584
- fi
667
+ if _install_bv_tool; then
668
+ installed_count=$((installed_count + 1))
585
669
  fi
586
670
 
587
- # beads-ui (Node.js)
588
- if command -v npm &>/dev/null; then
589
- read -r -p " Install beads-ui (Web dashboard)? [Y/n]: " install_web
590
- if [[ "$install_web" =~ ^[Yy]?$ ]]; then
591
- if run_with_spinner "Installing beads-ui" npm_global_install beads-ui; then
592
- print_info "Run: beads-ui"
593
- ((++installed_count))
594
- fi
595
- fi
596
-
597
- read -r -p " Install bdui (React/Ink TUI)? [Y/n]: " install_bdui
598
- if [[ "$install_bdui" =~ ^[Yy]?$ ]]; then
599
- if run_with_spinner "Installing bdui" npm_global_install bdui; then
600
- print_info "Run: bdui"
601
- ((++installed_count))
602
- fi
603
- fi
604
- fi
671
+ # beads-ui and bdui (Node.js)
672
+ local node_count
673
+ node_count=$(_install_beads_node_tools)
674
+ installed_count=$((installed_count + node_count))
605
675
 
606
676
  # perles (Rust)
607
- if command -v cargo &>/dev/null; then
608
- read -r -p " Install perles (BQL query language TUI)? [Y/n]: " install_perles
609
- if [[ "$install_perles" =~ ^[Yy]?$ ]]; then
610
- if run_with_spinner "Installing perles (Rust compile)" cargo install perles; then
611
- print_info "Run: perles"
612
- ((++installed_count))
613
- fi
614
- fi
677
+ if _install_perles; then
678
+ installed_count=$((installed_count + 1))
615
679
  fi
616
680
 
617
681
  if [[ $installed_count -gt 0 ]]; 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.1.135
13
+ # Version: 3.1.137
14
14
  #
15
15
  # Quick Install:
16
16
  # npm install -g aidevops && aidevops update (recommended)