aidevops 3.1.270 → 3.1.272

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.270
1
+ 3.1.272
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.270
6
+ # Version: 3.1.272
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.270",
3
+ "version": "3.1.272",
4
4
  "description": "AI DevOps Framework - AI-assisted development workflows, code quality, and deployment automation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -324,14 +324,33 @@ deploy_aidevops_agents() {
324
324
  inject_agents_reference() {
325
325
  print_info "Adding aidevops reference to AI assistant configurations..."
326
326
 
327
+ # Delegate to prompt-injection-adapter.sh (t1665.3) which handles all runtimes.
328
+ # The adapter deploys AGENTS.md references via each runtime's native mechanism:
329
+ # OpenCode (json-instructions), Claude (AGENTS.md autodiscovery), Codex, Cursor,
330
+ # Droid, Gemini, Windsurf, Continue, Kilo, Kiro, Aider.
331
+ local adapter_script="${INSTALL_DIR}/.agents/scripts/prompt-injection-adapter.sh"
332
+
333
+ if [[ -f "$adapter_script" ]]; then
334
+ # shellcheck source=/dev/null
335
+ source "$adapter_script"
336
+ deploy_prompts_for_all_runtimes
337
+ else
338
+ # Fallback: adapter not yet deployed — use legacy inline logic
339
+ # This path is only hit during initial setup before .agents/ is deployed.
340
+ print_warning "prompt-injection-adapter.sh not found — using legacy deployment"
341
+ _inject_agents_reference_legacy
342
+ fi
343
+
344
+ return 0
345
+ }
346
+
347
+ # Legacy fallback for inject_agents_reference — used only when the adapter
348
+ # script is not yet available (e.g., during initial setup before .agents/ deploy).
349
+ # Will be removed once t1665 migration is complete.
350
+ _inject_agents_reference_legacy() {
327
351
  local reference_line='Add ~/.aidevops/agents/AGENTS.md to context for AI DevOps capabilities.'
328
352
 
329
353
  # AI assistant agent directories - these receive AGENTS.md reference
330
- # Format: "config_dir:agents_subdir" where agents_subdir is the folder containing agent files
331
- # Only Claude Code (companion CLI) and .opencode are included here.
332
- # OpenCode excluded: its agent/ dir treats every .md as a subagent, so AGENTS.md
333
- # would show as a mode. OpenCode gets the reference via opencode.json instructions
334
- # field and the config-root AGENTS.md (deployed by deploy_opencode_greeting below).
335
354
  local ai_agent_dirs=(
336
355
  "$HOME/.claude:commands"
337
356
  "$HOME/.opencode:."
@@ -347,16 +366,12 @@ inject_agents_reference() {
347
366
 
348
367
  # Only process if the config directory exists (tool is installed)
349
368
  if [[ -d "$config_dir" ]]; then
350
- # Create agents subdirectory if needed
351
369
  mkdir -p "$agents_dir"
352
370
 
353
- # Check if AGENTS.md exists and has our reference
354
371
  if [[ -f "$agents_file" ]]; then
355
- # Check first line for our reference
356
372
  local first_line
357
373
  first_line=$(head -1 "$agents_file" 2>/dev/null || echo "")
358
- if [[ "$first_line" != *"~/.aidevops/agents/AGENTS.md"* ]]; then
359
- # Prepend reference to existing file
374
+ if [[ "$first_line" != *"aidevops/agents/AGENTS.md"* ]]; then
360
375
  local temp_file
361
376
  temp_file=$(mktemp)
362
377
  trap 'rm -f "${temp_file:-}"' RETURN
@@ -370,7 +385,6 @@ inject_agents_reference() {
370
385
  print_info "Reference already exists in $agents_file"
371
386
  fi
372
387
  else
373
- # Create new file with just the reference
374
388
  echo "$reference_line" >"$agents_file"
375
389
  print_success "Created $agents_file with aidevops reference"
376
390
  ((++updated_count))
@@ -384,17 +398,15 @@ inject_agents_reference() {
384
398
  print_success "Updated $updated_count AI assistant configuration(s)"
385
399
  fi
386
400
 
387
- # Clean up stale AGENTS.md from OpenCode agent dir (was incorrectly showing as subagent)
401
+ # Clean up stale AGENTS.md from OpenCode agent dir
388
402
  rm -f "$HOME/.config/opencode/agent/AGENTS.md"
389
403
 
390
404
  # Deploy OpenCode config-level AGENTS.md from managed template
391
- # This controls the session greeting (auto-loaded by OpenCode from config root)
392
405
  local opencode_config_dir="$HOME/.config/opencode"
393
406
  local opencode_config_agents="$opencode_config_dir/AGENTS.md"
394
407
  local template_source="$INSTALL_DIR/templates/opencode-config-agents.md"
395
408
 
396
409
  if [[ -d "$opencode_config_dir" && -f "$template_source" ]]; then
397
- # Backup if file exists and differs from template
398
410
  if [[ -f "$opencode_config_agents" ]]; then
399
411
  if ! diff -q "$template_source" "$opencode_config_agents" &>/dev/null; then
400
412
  create_backup_with_rotation "$opencode_config_agents" "opencode-agents"
@@ -407,6 +419,113 @@ inject_agents_reference() {
407
419
  fi
408
420
  fi
409
421
 
422
+ # Deploy Codex instructions.md (Codex reads ~/.codex/instructions.md as system prompt)
423
+ _deploy_codex_instructions
424
+
425
+ # Deploy Cursor AGENTS.md (Cursor reads ~/.cursor/rules/*.md as context)
426
+ _deploy_cursor_agents_reference
427
+
428
+ # Deploy Droid AGENTS.md (Droid reads ~/.factory/skills/*.md as context)
429
+ _deploy_droid_agents_reference
430
+
431
+ return 0
432
+ }
433
+
434
+ # Deploy instructions.md to Codex config directory.
435
+ # Codex reads ~/.codex/instructions.md as its system-level instructions.
436
+ _deploy_codex_instructions() {
437
+ local codex_dir="$HOME/.codex"
438
+ local instructions_file="$codex_dir/instructions.md"
439
+
440
+ # Only deploy if Codex is installed or config dir exists
441
+ if [[ ! -d "$codex_dir" ]] && ! command -v codex >/dev/null 2>&1; then
442
+ return 0
443
+ fi
444
+
445
+ mkdir -p "$codex_dir"
446
+
447
+ local reference_content
448
+ reference_content="Add ~/.aidevops/agents/AGENTS.md to context for AI DevOps capabilities."
449
+
450
+ if [[ -f "$instructions_file" ]]; then
451
+ # Check if our reference is already present
452
+ # shellcheck disable=SC2088 # Tilde is a literal grep pattern, not a path
453
+ if grep -q '~/.aidevops/agents/AGENTS.md' "$instructions_file" 2>/dev/null; then
454
+ print_info "Codex instructions.md already has aidevops reference"
455
+ return 0
456
+ fi
457
+ # Prepend reference to existing instructions
458
+ local temp_file
459
+ temp_file=$(mktemp)
460
+ echo "$reference_content" >"$temp_file"
461
+ echo "" >>"$temp_file"
462
+ cat "$instructions_file" >>"$temp_file"
463
+ mv "$temp_file" "$instructions_file"
464
+ print_success "Added aidevops reference to $instructions_file"
465
+ else
466
+ echo "$reference_content" >"$instructions_file"
467
+ print_success "Created $instructions_file with aidevops reference"
468
+ fi
469
+ return 0
470
+ }
471
+
472
+ # Deploy AGENTS.md reference to Cursor rules directory.
473
+ # Cursor reads ~/.cursor/rules/*.md files as additional context.
474
+ _deploy_cursor_agents_reference() {
475
+ local cursor_dir="$HOME/.cursor"
476
+ local rules_dir="$cursor_dir/rules"
477
+ local agents_file="$rules_dir/aidevops.md"
478
+
479
+ # Only deploy if Cursor is installed or config dir exists
480
+ if [[ ! -d "$cursor_dir" ]] && ! command -v cursor >/dev/null 2>&1 && ! command -v agent >/dev/null 2>&1; then
481
+ return 0
482
+ fi
483
+
484
+ mkdir -p "$rules_dir"
485
+
486
+ local reference_content
487
+ reference_content="Add ~/.aidevops/agents/AGENTS.md to context for AI DevOps capabilities."
488
+
489
+ if [[ -f "$agents_file" ]]; then
490
+ # shellcheck disable=SC2088 # Tilde is a literal grep pattern, not a path
491
+ if grep -q '~/.aidevops/agents/AGENTS.md' "$agents_file" 2>/dev/null; then
492
+ print_info "Cursor rules/aidevops.md already has aidevops reference"
493
+ return 0
494
+ fi
495
+ fi
496
+
497
+ echo "$reference_content" >"$agents_file"
498
+ print_success "Deployed aidevops reference to $agents_file"
499
+ return 0
500
+ }
501
+
502
+ # Deploy AGENTS.md reference to Droid skills directory.
503
+ # Droid reads ~/.factory/skills/*.md files as additional context.
504
+ _deploy_droid_agents_reference() {
505
+ local factory_dir="$HOME/.factory"
506
+ local skills_dir="$factory_dir/skills"
507
+ local agents_file="$skills_dir/aidevops.md"
508
+
509
+ # Only deploy if Droid is installed or config dir exists
510
+ if [[ ! -d "$factory_dir" ]] && ! command -v droid >/dev/null 2>&1; then
511
+ return 0
512
+ fi
513
+
514
+ mkdir -p "$skills_dir"
515
+
516
+ local reference_content
517
+ reference_content="Add ~/.aidevops/agents/AGENTS.md to context for AI DevOps capabilities."
518
+
519
+ if [[ -f "$agents_file" ]]; then
520
+ # shellcheck disable=SC2088 # Tilde is a literal grep pattern, not a path
521
+ if grep -q '~/.aidevops/agents/AGENTS.md' "$agents_file" 2>/dev/null; then
522
+ print_info "Droid skills/aidevops.md already has aidevops reference"
523
+ return 0
524
+ fi
525
+ fi
526
+
527
+ echo "$reference_content" >"$agents_file"
528
+ print_success "Deployed aidevops reference to $agents_file"
410
529
  return 0
411
530
  }
412
531
 
@@ -108,26 +108,31 @@ update_opencode_config() {
108
108
 
109
109
  print_info "Updating OpenCode configuration..."
110
110
 
111
- # Generate OpenCode commands (independent of opencode.json writes to ~/.config/opencode/command/)
112
- _run_generator ".agents/scripts/generate-opencode-commands.sh" \
113
- "Generating OpenCode commands..." \
114
- "OpenCode commands configured" \
115
- "OpenCode command generation encountered issues"
116
-
117
- # Generate OpenCode agent configuration (creates opencode.json if missing)
118
- # - Primary agents: Added to opencode.json (for Tab order & MCP control)
119
- # - Subagents: Generated as markdown in ~/.config/opencode/agent/
120
- _run_generator ".agents/scripts/generate-opencode-agents.sh" \
121
- "Generating OpenCode agent configuration..." \
122
- "OpenCode agents configured (11 primary in JSON, subagents as markdown)" \
123
- "OpenCode agent generation encountered issues"
124
-
125
- # Regenerate subagent index for plugin startup (t1040)
126
- _run_generator ".agents/scripts/subagent-index-helper.sh" \
127
- "Regenerating subagent index..." \
128
- "Subagent index regenerated" \
129
- "Subagent index generation encountered issues" \
130
- generate
111
+ # Use unified generator (t1665.4) if available, fall back to legacy scripts
112
+ if [[ -f ".agents/scripts/generate-runtime-config.sh" ]]; then
113
+ _run_generator ".agents/scripts/generate-runtime-config.sh" \
114
+ "Generating OpenCode configuration (unified)..." \
115
+ "OpenCode configuration complete (agents, commands, MCPs, prompts)" \
116
+ "OpenCode configuration encountered issues" \
117
+ all --runtime opencode
118
+ else
119
+ # Legacy fallback remove after one release cycle
120
+ _run_generator ".agents/scripts/generate-opencode-commands.sh" \
121
+ "Generating OpenCode commands..." \
122
+ "OpenCode commands configured" \
123
+ "OpenCode command generation encountered issues"
124
+
125
+ _run_generator ".agents/scripts/generate-opencode-agents.sh" \
126
+ "Generating OpenCode agent configuration..." \
127
+ "OpenCode agents configured (11 primary in JSON, subagents as markdown)" \
128
+ "OpenCode agent generation encountered issues"
129
+
130
+ _run_generator ".agents/scripts/subagent-index-helper.sh" \
131
+ "Regenerating subagent index..." \
132
+ "Subagent index regenerated" \
133
+ "Subagent index generation encountered issues" \
134
+ generate
135
+ fi
131
136
 
132
137
  return 0
133
138
  }
@@ -141,25 +146,250 @@ update_claude_config() {
141
146
 
142
147
  print_info "Updating Claude Code configuration..."
143
148
 
144
- # Generate Claude Code commands (writes to ~/.claude/commands/)
145
- _run_generator ".agents/scripts/generate-claude-commands.sh" \
146
- "Generating Claude Code commands..." \
147
- "Claude Code commands configured" \
148
- "Claude Code command generation encountered issues"
149
-
150
- # Generate Claude Code agent configuration (MCPs, settings.json, slash commands)
151
- # Mirrors update_opencode_config() calling generate-opencode-agents.sh (t1161.4)
152
- _run_generator ".agents/scripts/generate-claude-agents.sh" \
153
- "Generating Claude Code agent configuration..." \
154
- "Claude Code agents configured (MCPs, settings, commands)" \
155
- "Claude Code agent generation encountered issues"
156
-
157
- # Regenerate subagent index (shared between OpenCode and Claude Code)
158
- _run_generator ".agents/scripts/subagent-index-helper.sh" \
159
- "Regenerating subagent index..." \
160
- "Subagent index regenerated" \
161
- "Subagent index generation encountered issues" \
162
- generate
149
+ # Use unified generator (t1665.4) if available, fall back to legacy scripts
150
+ if [[ -f ".agents/scripts/generate-runtime-config.sh" ]]; then
151
+ _run_generator ".agents/scripts/generate-runtime-config.sh" \
152
+ "Generating Claude Code configuration (unified)..." \
153
+ "Claude Code configuration complete (agents, commands, MCPs, prompts)" \
154
+ "Claude Code configuration encountered issues" \
155
+ all --runtime claude-code
156
+ else
157
+ # Legacy fallback — remove after one release cycle
158
+ _run_generator ".agents/scripts/generate-claude-commands.sh" \
159
+ "Generating Claude Code commands..." \
160
+ "Claude Code commands configured" \
161
+ "Claude Code command generation encountered issues"
162
+
163
+ _run_generator ".agents/scripts/generate-claude-agents.sh" \
164
+ "Generating Claude Code agent configuration..." \
165
+ "Claude Code agents configured (MCPs, settings, commands)" \
166
+ "Claude Code agent generation encountered issues"
167
+
168
+ _run_generator ".agents/scripts/subagent-index-helper.sh" \
169
+ "Regenerating subagent index..." \
170
+ "Subagent index regenerated" \
171
+ "Subagent index generation encountered issues" \
172
+ generate
173
+ fi
174
+
175
+ return 0
176
+ }
177
+
178
+ # Unified runtime config update (t1665.4)
179
+ # Generates config for all installed runtimes in a single pass.
180
+ # Called by setup.sh as an alternative to separate update_opencode_config + update_claude_config.
181
+ # Respects per-runtime opt-outs (manage_opencode_config, manage_claude_config).
182
+ update_runtime_configs() {
183
+ print_info "Updating runtime configurations..."
184
+
185
+ if [[ ! -f ".agents/scripts/generate-runtime-config.sh" ]]; then
186
+ # Legacy fallback — use per-runtime update functions
187
+ print_info "Unified generator not found — falling back to per-runtime updates"
188
+ update_opencode_config
189
+ update_claude_config
190
+ return 0
191
+ fi
192
+
193
+ # Build list of runtimes to generate, respecting opt-outs
194
+ local runtimes_to_generate=()
195
+
196
+ if is_feature_enabled manage_opencode_config 2>/dev/null; then
197
+ runtimes_to_generate+=("opencode")
198
+ else
199
+ print_info "OpenCode config management disabled via config"
200
+ fi
201
+
202
+ if is_feature_enabled manage_claude_config 2>/dev/null; then
203
+ runtimes_to_generate+=("claude-code")
204
+ else
205
+ print_info "Claude Code config management disabled via config"
206
+ fi
207
+
208
+ # Generate for each enabled runtime
209
+ local runtime
210
+ for runtime in "${runtimes_to_generate[@]}"; do
211
+ _run_generator ".agents/scripts/generate-runtime-config.sh" \
212
+ "Generating configuration for $runtime..." \
213
+ "$runtime configuration updated" \
214
+ "$runtime configuration encountered issues" \
215
+ all --runtime "$runtime"
216
+ done
217
+
218
+ return 0
219
+ }
220
+
221
+ update_codex_config() {
222
+ # Only run if Codex is installed or config dir exists
223
+ if [[ ! -d "$HOME/.codex" ]] && ! command -v codex >/dev/null 2>&1; then
224
+ return 0
225
+ fi
226
+
227
+ print_info "Updating Codex configuration..."
228
+
229
+ # Fix broken MCP_DOCKER entry (P0 — OrbStack/Colima don't support docker mcp)
230
+ if type _fix_codex_docker_mcp &>/dev/null; then
231
+ _fix_codex_docker_mcp
232
+ fi
233
+
234
+ # Deploy aidevops MCP servers to Codex config.toml
235
+ _deploy_codex_mcps
236
+
237
+ print_success "Codex configuration updated"
238
+ return 0
239
+ }
240
+
241
+ # Deploy standard aidevops MCP servers to ~/.codex/config.toml
242
+ # Codex uses TOML format: [mcp_servers.NAME] sections
243
+ _deploy_codex_mcps() {
244
+ local config="$HOME/.codex/config.toml"
245
+ mkdir -p "$HOME/.codex"
246
+
247
+ # Touch config if it doesn't exist
248
+ [[ -f "$config" ]] || touch "$config"
249
+
250
+ local mcp_count=0
251
+
252
+ # Helper: add a TOML MCP section if not already present
253
+ # Args: $1=name, $2=type (stdio|url), $3=command_or_url, $4=args (optional, comma-separated)
254
+ _add_codex_mcp() {
255
+ local name="$1"
256
+ local mcp_type="$2"
257
+ local cmd_or_url="$3"
258
+ local args="${4:-}"
259
+
260
+ if grep -q "\\[mcp_servers\\.${name}\\]" "$config" 2>/dev/null; then
261
+ echo -e " ${BLUE:-}=${NC:-} $name (already configured)"
262
+ return 0
263
+ fi
264
+
265
+ {
266
+ echo ""
267
+ echo "[mcp_servers.${name}]"
268
+ if [[ "$mcp_type" == "stdio" ]]; then
269
+ echo "command = '${cmd_or_url}'"
270
+ if [[ -n "$args" ]]; then
271
+ echo "args = [${args}]"
272
+ fi
273
+ else
274
+ echo "type = 'url'"
275
+ echo "url = '${cmd_or_url}'"
276
+ fi
277
+ } >>"$config"
278
+ ((++mcp_count))
279
+ echo -e " ${GREEN:-}+${NC:-} $name"
280
+ return 0
281
+ }
282
+
283
+ # --- context7 (library docs) ---
284
+ _add_codex_mcp "context7" "stdio" "npx" "'-y', '@upstash/context7-mcp@latest'"
285
+
286
+ # --- Playwright MCP ---
287
+ _add_codex_mcp "playwright" "stdio" "npx" "'-y', '@anthropic-ai/mcp-server-playwright@latest'"
288
+
289
+ # --- shadcn UI ---
290
+ _add_codex_mcp "shadcn" "stdio" "npx" "'shadcn@latest', 'mcp'"
291
+
292
+ # --- OpenAPI Search (remote, zero install) ---
293
+ _add_codex_mcp "openapi-search" "url" "https://openapi-mcp.openapisearch.com/mcp"
294
+
295
+ # --- Cloudflare API (remote) ---
296
+ _add_codex_mcp "cloudflare-api" "url" "https://mcp.cloudflare.com/mcp"
297
+
298
+ echo -e " ${GREEN:-}Done${NC:-} -- $mcp_count new MCP servers added to Codex config"
299
+ return 0
300
+ }
301
+
302
+ update_cursor_config() {
303
+ # Only run if Cursor is installed or config dir exists
304
+ if [[ ! -d "$HOME/.cursor" ]] && ! command -v cursor >/dev/null 2>&1 && ! command -v agent >/dev/null 2>&1; then
305
+ return 0
306
+ fi
307
+
308
+ print_info "Updating Cursor configuration..."
309
+
310
+ # Deploy aidevops MCP servers to Cursor mcp.json
311
+ _deploy_cursor_mcps
312
+
313
+ print_success "Cursor configuration updated"
314
+ return 0
315
+ }
316
+
317
+ # Deploy standard aidevops MCP servers to ~/.cursor/mcp.json
318
+ # Cursor uses JSON format: { "mcpServers": { "name": { ... } } }
319
+ _deploy_cursor_mcps() {
320
+ local config="$HOME/.cursor/mcp.json"
321
+ mkdir -p "$HOME/.cursor"
322
+
323
+ # Ensure config file exists with valid JSON
324
+ if [[ ! -f "$config" ]]; then
325
+ echo '{}' >"$config"
326
+ fi
327
+
328
+ # Use the json_set_nested helper from ai-cli-config.sh if available,
329
+ # otherwise use python3 directly
330
+ local mcp_count=0
331
+
332
+ # Helper: add a JSON MCP entry if not already present
333
+ # Increments mcp_count only when a new entry is actually added.
334
+ _add_cursor_mcp() {
335
+ local name="$1"
336
+ local json_value="$2"
337
+
338
+ if ! command -v python3 >/dev/null 2>&1; then
339
+ print_warning "python3 not found - cannot update Cursor config"
340
+ return 0
341
+ fi
342
+
343
+ local py_output
344
+ py_output=$(
345
+ python3 - "$config" "$name" "$json_value" <<'PYEOF'
346
+ import json, sys
347
+
348
+ file_path = sys.argv[1]
349
+ name = sys.argv[2]
350
+ value_json = sys.argv[3]
351
+
352
+ try:
353
+ with open(file_path, 'r') as f:
354
+ cfg = json.load(f)
355
+ except (FileNotFoundError, json.JSONDecodeError):
356
+ cfg = {}
357
+
358
+ if "mcpServers" not in cfg or not isinstance(cfg["mcpServers"], dict):
359
+ cfg["mcpServers"] = {}
360
+
361
+ if name in cfg["mcpServers"]:
362
+ print(f"SKIP = {name} (already configured)")
363
+ else:
364
+ cfg["mcpServers"][name] = json.loads(value_json)
365
+ with open(file_path, 'w') as f:
366
+ json.dump(cfg, f, indent=2)
367
+ f.write('\n')
368
+ print(f"ADDED + {name}")
369
+ PYEOF
370
+ ) || true
371
+ echo " ${py_output#* }"
372
+ if [[ "$py_output" == ADDED* ]]; then
373
+ ((++mcp_count))
374
+ fi
375
+ return 0
376
+ }
377
+
378
+ # --- context7 (library docs) ---
379
+ _add_cursor_mcp "context7" '{"command":"npx","args":["-y","@upstash/context7-mcp@latest"]}'
380
+
381
+ # --- Playwright MCP ---
382
+ _add_cursor_mcp "playwright" '{"command":"npx","args":["-y","@anthropic-ai/mcp-server-playwright@latest"]}'
383
+
384
+ # --- shadcn UI ---
385
+ _add_cursor_mcp "shadcn" '{"command":"npx","args":["shadcn@latest","mcp"]}'
386
+
387
+ # --- OpenAPI Search (remote, zero install) ---
388
+ _add_cursor_mcp "openapi-search" '{"url":"https://openapi-mcp.openapisearch.com/mcp"}'
389
+
390
+ # --- Cloudflare API (remote) ---
391
+ _add_cursor_mcp "cloudflare-api" '{"url":"https://mcp.cloudflare.com/mcp"}'
163
392
 
393
+ echo " Done -- $mcp_count new MCP servers added to Cursor config"
164
394
  return 0
165
395
  }
@@ -222,14 +222,15 @@ generate_agent_skills() {
222
222
  if [[ -f "$skills_script" ]]; then
223
223
  if bash "$skills_script" 2>/dev/null; then
224
224
  print_success "Agent Skills SKILL.md files generated"
225
+ return 0
225
226
  else
226
227
  print_warning "Agent Skills generation encountered issues (non-critical)"
228
+ return 1
227
229
  fi
228
230
  else
229
231
  print_warning "Agent Skills generator not found at $skills_script"
232
+ return 1
230
233
  fi
231
-
232
- return 0
233
234
  }
234
235
 
235
236
  create_skill_symlinks() {
@@ -135,33 +135,52 @@ print_final_instructions() {
135
135
  return 0
136
136
  }
137
137
 
138
- # Offer to launch onboarding for new users (only if not running inside OpenCode
139
- # and not non-interactive).
138
+ # Offer to launch onboarding for new users (only if not running inside an AI
139
+ # runtime session and not non-interactive). (t1665.5 — registry-driven)
140
140
  # Respects config: aidevops config set ui.onboarding_prompt false
141
141
  setup_onboarding_prompt() {
142
- if [[ "$NON_INTERACTIVE" != "true" ]] && [[ -z "${OPENCODE_SESSION:-}" ]] && is_feature_enabled onboarding_prompt 2>/dev/null && command -v opencode &>/dev/null; then
143
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
144
- echo ""
145
- echo "Ready to configure your services?"
142
+ # Skip if non-interactive or already inside a runtime session
143
+ [[ "$NON_INTERACTIVE" == "true" ]] && return 0
144
+ [[ -n "${OPENCODE_SESSION:-}" || -n "${CLAUDE_SESSION:-}" ]] && return 0
145
+ is_feature_enabled onboarding_prompt 2>/dev/null || return 0
146
+
147
+ # Find first available headless runtime for onboarding dispatch
148
+ local _onb_bin="" _onb_name=""
149
+ if type rt_list_headless &>/dev/null; then
150
+ local _onb_rt_id
151
+ while IFS= read -r _onb_rt_id; do
152
+ _onb_bin=$(rt_binary "$_onb_rt_id") || continue
153
+ if [[ -n "$_onb_bin" ]] && command -v "$_onb_bin" &>/dev/null; then
154
+ _onb_name=$(rt_display_name "$_onb_rt_id") || _onb_name="$_onb_bin"
155
+ break
156
+ fi
157
+ _onb_bin=""
158
+ done < <(rt_list_headless)
159
+ fi
160
+ # Fallback
161
+ if [[ -z "$_onb_bin" ]] && command -v opencode &>/dev/null; then
162
+ _onb_bin="opencode"
163
+ _onb_name="OpenCode"
164
+ fi
165
+ [[ -z "$_onb_bin" ]] && return 0
166
+
167
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
168
+ echo ""
169
+ echo "Ready to configure your services?"
170
+ echo ""
171
+ echo "Launch ${_onb_name} with the onboarding wizard to:"
172
+ echo " - See which services are already configured"
173
+ echo " - Get personalized recommendations based on your work"
174
+ echo " - Set up API keys and credentials interactively"
175
+ echo ""
176
+ read -r -p "Launch ${_onb_name} with /onboarding now? [Y/n]: " launch_onboarding
177
+ if [[ "$launch_onboarding" =~ ^[Yy]?$ ]]; then
146
178
  echo ""
147
- echo "Launch OpenCode with the onboarding wizard to:"
148
- echo " - See which services are already configured"
149
- echo " - Get personalized recommendations based on your work"
150
- echo " - Set up API keys and credentials interactively"
179
+ echo "Starting ${_onb_name} with onboarding wizard..."
180
+ "$_onb_bin" --prompt "/onboarding"
181
+ else
151
182
  echo ""
152
- read -r -p "Launch OpenCode with /onboarding now? [Y/n]: " launch_onboarding
153
- if [[ "$launch_onboarding" =~ ^[Yy]?$ ]]; then
154
- echo ""
155
- echo "Starting OpenCode with onboarding wizard..."
156
- # Launch with /onboarding prompt only — don't use --agent flag because
157
- # the "Onboarding" agent only exists after generate-opencode-agents.sh
158
- # writes to opencode.json, which requires opencode.json to already exist.
159
- # On first run it won't, so --agent "Onboarding" causes a fatal error.
160
- opencode --prompt "/onboarding"
161
- else
162
- echo ""
163
- echo "You can run /onboarding anytime in OpenCode to configure services."
164
- fi
183
+ echo "You can run /onboarding anytime in ${_onb_name} to configure services."
165
184
  fi
166
185
  return 0
167
186
  }
@@ -150,9 +150,20 @@ setup_supervisor_pulse() {
150
150
  _pulse_installed=true
151
151
  fi
152
152
 
153
- # Detect opencode binary location
153
+ # Detect dispatch backend binary location (t1665.5 — registry-driven)
154
154
  local opencode_bin
155
- opencode_bin=$(command -v opencode 2>/dev/null || echo "/opt/homebrew/bin/opencode")
155
+ if type rt_list_headless &>/dev/null; then
156
+ local _sched_rt_id _sched_bin
157
+ while IFS= read -r _sched_rt_id; do
158
+ _sched_bin=$(rt_binary "$_sched_rt_id") || continue
159
+ if [[ -n "$_sched_bin" ]] && command -v "$_sched_bin" &>/dev/null; then
160
+ opencode_bin=$(command -v "$_sched_bin")
161
+ break
162
+ fi
163
+ done < <(rt_list_headless)
164
+ fi
165
+ # Fallback if registry not loaded or no runtime found
166
+ opencode_bin="${opencode_bin:-$(command -v opencode 2>/dev/null || echo "/opt/homebrew/bin/opencode")}"
156
167
 
157
168
  if [[ "$_do_install" == "true" ]]; then
158
169
  mkdir -p "$HOME/.aidevops/logs"
@@ -1535,6 +1535,150 @@ setup_opencode_cli() {
1535
1535
  return 0
1536
1536
  }
1537
1537
 
1538
+ setup_codex_cli() {
1539
+ print_info "Setting up OpenAI Codex CLI..."
1540
+
1541
+ # Check if Codex is already installed
1542
+ if command -v codex >/dev/null 2>&1; then
1543
+ local codex_version
1544
+ codex_version=$(codex --version 2>/dev/null | head -1 || echo "unknown")
1545
+ print_success "Codex already installed: $codex_version"
1546
+ # Fix broken MCP_DOCKER if present
1547
+ _fix_codex_docker_mcp
1548
+ return 0
1549
+ fi
1550
+
1551
+ # Need either bun or npm to install
1552
+ local installer=""
1553
+ local install_pkg="@openai/codex@latest"
1554
+
1555
+ if command -v bun >/dev/null 2>&1; then
1556
+ installer="bun"
1557
+ elif command -v npm >/dev/null 2>&1; then
1558
+ installer="npm"
1559
+ else
1560
+ print_warning "Neither bun nor npm found - cannot install Codex"
1561
+ print_info "Install Node.js first, then re-run setup"
1562
+ return 0
1563
+ fi
1564
+
1565
+ print_info "Codex is OpenAI's AI coding CLI (terminal-based, agentic)"
1566
+ echo " It provides an AI-powered terminal interface using OpenAI models."
1567
+ echo ""
1568
+
1569
+ local install_codex="Y"
1570
+ if [[ "${NON_INTERACTIVE:-}" != "true" ]]; then
1571
+ read -r -p "Install Codex via $installer? [Y/n]: " install_codex || install_codex="Y"
1572
+ fi
1573
+ if [[ "$install_codex" =~ ^[Yy]?$ ]]; then
1574
+ if run_with_spinner "Installing Codex" npm_global_install "$install_pkg"; then
1575
+ print_success "Codex installed"
1576
+ echo ""
1577
+ print_info "Codex needs OpenAI authentication."
1578
+ print_info "Run 'codex' and follow the auth prompts."
1579
+ echo ""
1580
+ # Fix broken MCP_DOCKER if Codex created a default config
1581
+ _fix_codex_docker_mcp
1582
+ else
1583
+ print_warning "Codex installation failed"
1584
+ print_info "Try manually: npm install -g $install_pkg"
1585
+ fi
1586
+ else
1587
+ print_info "Skipped Codex installation"
1588
+ print_info "Install later: $installer install -g $install_pkg"
1589
+ fi
1590
+
1591
+ return 0
1592
+ }
1593
+
1594
+ # P0 fix: Remove broken MCP_DOCKER from Codex config.toml
1595
+ # Docker Desktop 4.40+ with MCP Toolkit extension is required for `docker mcp`.
1596
+ # OrbStack, Colima, Rancher Desktop do not support it.
1597
+ _fix_codex_docker_mcp() {
1598
+ local config="$HOME/.codex/config.toml"
1599
+ [[ -f "$config" ]] || return 0
1600
+
1601
+ # Check if MCP_DOCKER section exists
1602
+ if ! grep -q '^\[mcp_servers\.MCP_DOCKER\]' "$config" 2>/dev/null; then
1603
+ return 0
1604
+ fi
1605
+
1606
+ # Check if `docker mcp` subcommand is actually available
1607
+ if docker mcp --help >/dev/null 2>&1; then
1608
+ return 0
1609
+ fi
1610
+
1611
+ # Comment out the MCP_DOCKER section (from header to next section or EOF)
1612
+ # Use sed to comment out lines from [mcp_servers.MCP_DOCKER] to the next
1613
+ # section header or end of file. Portable sed (no -i on macOS without ext).
1614
+ local tmp_config
1615
+ tmp_config=$(mktemp)
1616
+ local in_mcp_docker=false
1617
+ while IFS= read -r line || [[ -n "$line" ]]; do
1618
+ if [[ "$line" == "[mcp_servers.MCP_DOCKER]" ]]; then
1619
+ in_mcp_docker=true
1620
+ printf '# %s # Disabled by aidevops: docker mcp not available\n' "$line" >>"$tmp_config"
1621
+ continue
1622
+ fi
1623
+ # If we hit another section header, stop commenting
1624
+ if [[ "$in_mcp_docker" == "true" ]] && [[ "$line" == "["* ]]; then
1625
+ in_mcp_docker=false
1626
+ fi
1627
+ if [[ "$in_mcp_docker" == "true" ]]; then
1628
+ printf '# %s\n' "$line" >>"$tmp_config"
1629
+ else
1630
+ printf '%s\n' "$line" >>"$tmp_config"
1631
+ fi
1632
+ done <"$config"
1633
+ mv "$tmp_config" "$config"
1634
+ print_info "Disabled MCP_DOCKER in Codex config (docker mcp not available on this system)"
1635
+ return 0
1636
+ }
1637
+
1638
+ setup_droid_cli() {
1639
+ print_info "Setting up Factory.AI Droid CLI..."
1640
+
1641
+ # Check if Droid is already installed
1642
+ if command -v droid >/dev/null 2>&1; then
1643
+ local droid_version
1644
+ droid_version=$(droid --version 2>/dev/null | head -1 || echo "unknown")
1645
+ print_success "Droid already installed: $droid_version"
1646
+ return 0
1647
+ fi
1648
+
1649
+ # Droid uses its own installer — not available via npm/brew
1650
+ print_info "Droid (Factory.AI) is an AI coding agent CLI"
1651
+ echo " It provides autonomous coding capabilities with Factory.AI models."
1652
+ echo ""
1653
+
1654
+ local install_droid="Y"
1655
+ if [[ "${NON_INTERACTIVE:-}" != "true" ]]; then
1656
+ read -r -p "Install Droid CLI? [Y/n]: " install_droid || install_droid="Y"
1657
+ fi
1658
+ if [[ "$install_droid" =~ ^[Yy]?$ ]]; then
1659
+ print_info "Installing Droid CLI..."
1660
+ if command -v curl >/dev/null 2>&1; then
1661
+ if curl -fsSL https://app.factory.ai/install.sh | bash 2>/dev/null; then
1662
+ print_success "Droid installed"
1663
+ echo ""
1664
+ print_info "Run 'droid auth login' to authenticate with Factory.AI."
1665
+ echo ""
1666
+ else
1667
+ print_warning "Droid installation failed"
1668
+ print_info "Install manually from: https://docs.factory.ai/cli/installation"
1669
+ fi
1670
+ else
1671
+ print_warning "curl not found - cannot install Droid"
1672
+ print_info "Install manually from: https://docs.factory.ai/cli/installation"
1673
+ fi
1674
+ else
1675
+ print_info "Skipped Droid installation"
1676
+ print_info "Install later: curl -fsSL https://app.factory.ai/install.sh | bash"
1677
+ fi
1678
+
1679
+ return 0
1680
+ }
1681
+
1538
1682
  setup_google_workspace_cli() {
1539
1683
  print_info "Setting up Google Workspace CLI (gws)..."
1540
1684
 
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.270
13
+ # Version: 3.1.272
14
14
  #
15
15
  # Quick Install:
16
16
  # npm install -g aidevops && aidevops update (recommended)
@@ -689,27 +689,8 @@ init_settings_json() {
689
689
  return 0
690
690
  }
691
691
 
692
- # Main setup function
693
- main() {
694
- # Bootstrap first (handles curl install)
695
- bootstrap_repo "$@"
696
-
697
- parse_args "$@"
698
- local _os
699
- _os="$(uname -s)"
700
-
701
- # Auto-detect non-interactive terminals (CI/CD, agent shells, piped stdin)
702
- # Must run after parse_args so explicit --interactive flag takes precedence
703
- if [[ "$INTERACTIVE_MODE" != "true" && ! -t 0 ]]; then
704
- NON_INTERACTIVE=true
705
- fi
706
-
707
- # Guard: --interactive and --non-interactive are mutually exclusive
708
- if [[ "$INTERACTIVE_MODE" == "true" && "$NON_INTERACTIVE" == "true" ]]; then
709
- print_error "--interactive and --non-interactive cannot be used together"
710
- exit 1
711
- fi
712
-
692
+ # Print the setup header based on active mode flags.
693
+ _setup_print_header() {
713
694
  echo "🤖 AI DevOps Framework Setup"
714
695
  echo "============================="
715
696
  if [[ "$CLEAN_MODE" == "true" ]]; then
@@ -726,139 +707,157 @@ main() {
726
707
  echo "Mode: Update (will check for tool updates after setup)"
727
708
  fi
728
709
  echo ""
710
+ return 0
711
+ }
729
712
 
730
- # Non-interactive mode: deploy agents only, skip all optional installs
731
- if [[ "$NON_INTERACTIVE" == "true" ]]; then
732
- print_info "Non-interactive mode: deploying agents and running safe migrations only"
733
- verify_location
734
- check_requirements
735
- check_python_upgrade_available
736
- set_permissions
737
- migrate_old_backups
738
- migrate_loop_state_directories
739
- migrate_agent_to_agents_folder
740
- migrate_mcp_env_to_credentials
741
- migrate_pulse_repos_to_repos_json
742
- cleanup_deprecated_paths
743
- migrate_orphaned_supervisor
744
- cleanup_deprecated_mcps
745
- cleanup_stale_bun_opencode
746
- validate_opencode_config
747
- deploy_aidevops_agents
748
- sync_agent_sources
749
- setup_shellcheck_wrapper
750
- if is_feature_enabled safety_hooks 2>/dev/null; then
751
- setup_safety_hooks
752
- fi
753
- init_settings_json
713
+ # Non-interactive path: deploy agents and run safe migrations only (no prompts).
714
+ _setup_run_non_interactive() {
715
+ print_info "Non-interactive mode: deploying agents and running safe migrations only"
716
+ verify_location
717
+ check_requirements
718
+ check_python_upgrade_available
719
+ set_permissions
720
+ migrate_old_backups
721
+ migrate_loop_state_directories
722
+ migrate_agent_to_agents_folder
723
+ migrate_mcp_env_to_credentials
724
+ migrate_pulse_repos_to_repos_json
725
+ cleanup_deprecated_paths
726
+ migrate_orphaned_supervisor
727
+ cleanup_deprecated_mcps
728
+ cleanup_stale_bun_opencode
729
+ validate_opencode_config
730
+ deploy_aidevops_agents
731
+ sync_agent_sources
732
+ setup_shellcheck_wrapper
733
+ if is_feature_enabled safety_hooks 2>/dev/null; then
734
+ setup_safety_hooks
735
+ fi
736
+ init_settings_json
754
737
 
755
- # Parallelise independent skill operations (t1356: ~84s serial -> ~18s parallel)
756
- # generate_agent_skills (18s), create_skill_symlinks (<1s), and
757
- # scan_imported_skills (66s serial, ~10s with parallel scanning) are independent.
758
- generate_agent_skills &
759
- local _pid_skills=$!
738
+ # Parallelise independent skill operations (t1356: ~84s serial -> ~18s parallel)
739
+ # generate_agent_skills must complete before create_skill_symlinks (symlinks
740
+ # depend on generated SKILL.md files). scan_imported_skills is independent.
741
+ local _pid_symlinks=""
742
+ if generate_agent_skills; then
760
743
  create_skill_symlinks &
761
- local _pid_symlinks=$!
762
- scan_imported_skills &
763
- local _pid_scan=$!
764
- wait "$_pid_skills" 2>/dev/null || print_warning "Agent skills generation encountered issues (non-critical)"
744
+ _pid_symlinks=$!
745
+ else
746
+ print_warning "Agent skills generation failed — skipping skill symlinks"
747
+ fi
748
+
749
+ scan_imported_skills &
750
+ local _pid_scan=$!
751
+
752
+ if [[ -n "$_pid_symlinks" ]]; then
765
753
  wait "$_pid_symlinks" 2>/dev/null || print_warning "Skill symlink creation encountered issues (non-critical)"
766
- wait "$_pid_scan" 2>/dev/null || print_warning "Skill security scan encountered issues (non-critical)"
754
+ fi
755
+ wait "$_pid_scan" 2>/dev/null || print_warning "Skill security scan encountered issues (non-critical)"
756
+
757
+ inject_agents_reference
758
+ update_opencode_config
759
+ update_claude_config
760
+ update_codex_config
761
+ update_cursor_config
762
+ disable_ondemand_mcps
763
+ return 0
764
+ }
767
765
 
768
- inject_agents_reference
769
- if is_feature_enabled manage_opencode_config 2>/dev/null; then
770
- update_opencode_config
771
- else
772
- print_info "OpenCode config management disabled via config (integrations.manage_opencode_config)"
773
- fi
774
- if is_feature_enabled manage_claude_config 2>/dev/null; then
775
- update_claude_config
776
- else
777
- print_info "Claude config management disabled via config (integrations.manage_claude_config)"
778
- fi
779
- disable_ondemand_mcps
780
- else
781
- # Required steps (always run)
782
- verify_location
783
- check_requirements
784
-
785
- # Quality tools check (optional but recommended)
786
- confirm_step "Check quality tools (shellcheck, shfmt)" && check_quality_tools
787
-
788
- # Core runtime setup (early - many later steps depend on these)
789
- confirm_step "Setup Node.js runtime (required for OpenCode and tools)" && setup_nodejs
790
-
791
- # Shell environment setup (early, so later tools benefit from zsh/Oh My Zsh)
792
- confirm_step "Setup Oh My Zsh (optional, enhances zsh)" && setup_oh_my_zsh
793
- confirm_step "Setup cross-shell compatibility (preserve bash config in zsh)" && setup_shell_compatibility
794
-
795
- # OrbStack (macOS only - offer VM option early)
796
- confirm_step "Setup OrbStack (lightweight Linux VMs on macOS)" && setup_orbstack_vm
797
-
798
- # Optional steps with confirmation in interactive mode
799
- confirm_step "Check optional dependencies (bun, node, python)" && check_optional_deps
800
- confirm_step "Check Python version (recommend upgrade if outdated)" && check_python_upgrade_available
801
- confirm_step "Setup recommended tools (Tabby, Zed, etc.)" && setup_recommended_tools
802
- confirm_step "Setup MiniSim (iOS/Android emulator launcher)" && setup_minisim
803
- confirm_step "Setup ClaudeBar (AI quota monitor in menu bar)" && setup_claudebar
804
- confirm_step "Setup Git CLIs (gh, glab, tea)" && setup_git_clis
805
- confirm_step "Setup file discovery tools (fd, ripgrep, ripgrep-all)" && setup_file_discovery_tools
806
- confirm_step "Setup rtk (token-optimized CLI output, 60-90% savings)" && setup_rtk
807
- confirm_step "Setup shell linting tools (shellcheck, shfmt)" && setup_shell_linting_tools
766
+ # Interactive path: all optional steps gated behind confirm_step prompts.
767
+ _setup_run_interactive() {
768
+ # Required steps (always run)
769
+ verify_location
770
+ check_requirements
771
+
772
+ # Quality tools check (optional but recommended)
773
+ confirm_step "Check quality tools (shellcheck, shfmt)" && check_quality_tools
774
+
775
+ # Core runtime setup (early - many later steps depend on these)
776
+ confirm_step "Setup Node.js runtime (required for OpenCode and tools)" && setup_nodejs
777
+
778
+ # Shell environment setup (early, so later tools benefit from zsh/Oh My Zsh)
779
+ confirm_step "Setup Oh My Zsh (optional, enhances zsh)" && setup_oh_my_zsh
780
+ confirm_step "Setup cross-shell compatibility (preserve bash config in zsh)" && setup_shell_compatibility
781
+
782
+ # OrbStack (macOS only - offer VM option early)
783
+ confirm_step "Setup OrbStack (lightweight Linux VMs on macOS)" && setup_orbstack_vm
784
+
785
+ # Optional steps with confirmation in interactive mode
786
+ confirm_step "Check optional dependencies (bun, node, python)" && check_optional_deps
787
+ confirm_step "Check Python version (recommend upgrade if outdated)" && check_python_upgrade_available
788
+ confirm_step "Setup recommended tools (Tabby, Zed, etc.)" && setup_recommended_tools
789
+ confirm_step "Setup MiniSim (iOS/Android emulator launcher)" && setup_minisim
790
+ confirm_step "Setup ClaudeBar (AI quota monitor in menu bar)" && setup_claudebar
791
+ confirm_step "Setup Git CLIs (gh, glab, tea)" && setup_git_clis
792
+ confirm_step "Setup file discovery tools (fd, ripgrep, ripgrep-all)" && setup_file_discovery_tools
793
+ confirm_step "Setup rtk (token-optimized CLI output, 60-90% savings)" && setup_rtk
794
+ confirm_step "Setup shell linting tools (shellcheck, shfmt)" && {
795
+ setup_shell_linting_tools
808
796
  setup_shellcheck_wrapper
809
- confirm_step "Setup Qlty CLI (multi-linter code quality)" && setup_qlty_cli
810
- confirm_step "Rosetta audit (Apple Silicon x86 migration)" && setup_rosetta_audit
811
- confirm_step "Setup Worktrunk (git worktree management)" && setup_worktrunk
812
- confirm_step "Setup SSH key" && setup_ssh_key
813
- confirm_step "Setup configuration files" && setup_configs
814
- confirm_step "Set secure permissions on config files" && set_permissions
815
- confirm_step "Install aidevops CLI command" && install_aidevops_cli
816
- confirm_step "Setup shell aliases" && setup_aliases
817
- confirm_step "Setup terminal title integration" && setup_terminal_title
818
- confirm_step "Deploy AI templates to home directories" && deploy_ai_templates
819
- confirm_step "Migrate old backups to new structure" && migrate_old_backups
820
- confirm_step "Migrate loop state from .claude/.agent/ to .agents/loop-state/" && migrate_loop_state_directories
821
- confirm_step "Migrate .agent -> .agents in user projects" && migrate_agent_to_agents_folder
822
- confirm_step "Migrate mcp-env.sh -> credentials.sh" && migrate_mcp_env_to_credentials
823
- confirm_step "Migrate pulse-repos.json into repos.json" && migrate_pulse_repos_to_repos_json
824
- confirm_step "Cleanup deprecated agent paths" && cleanup_deprecated_paths
825
- confirm_step "Migrate orphaned supervisor to pulse-wrapper" && migrate_orphaned_supervisor
826
- confirm_step "Cleanup deprecated MCP entries (hetzner, serper, etc.)" && cleanup_deprecated_mcps
827
- confirm_step "Cleanup stale bun opencode install" && cleanup_stale_bun_opencode
828
- confirm_step "Validate and repair OpenCode config schema" && validate_opencode_config
829
- confirm_step "Extract OpenCode prompts" && extract_opencode_prompts
830
- confirm_step "Check OpenCode prompt drift" && check_opencode_prompt_drift
831
- confirm_step "Deploy aidevops agents to ~/.aidevops/agents/" && deploy_aidevops_agents
832
- confirm_step "Sync agents from private repositories" && sync_agent_sources
833
- confirm_step "Install Claude Code safety hooks (block destructive commands)" && setup_safety_hooks
834
- confirm_step "Initialize settings.json (canonical config file)" && init_settings_json
835
- confirm_step "Setup multi-tenant credential storage" && setup_multi_tenant_credentials
836
- confirm_step "Generate agent skills (SKILL.md files)" && generate_agent_skills
837
- confirm_step "Create symlinks for imported skills" && create_skill_symlinks
838
- confirm_step "Check for skill updates from upstream" && check_skill_updates
839
- confirm_step "Security scan imported skills" && scan_imported_skills
840
- confirm_step "Inject agents reference into AI configs" && inject_agents_reference
841
- confirm_step "Setup Python environment (DSPy, crawl4ai)" && setup_python_env
842
- confirm_step "Setup Node.js environment" && setup_nodejs_env
843
- confirm_step "Install MCP packages globally (fast startup)" && install_mcp_packages
844
- confirm_step "Setup LocalWP MCP server" && setup_localwp_mcp
845
- confirm_step "Setup Augment Context Engine MCP" && setup_augment_context_engine
846
- confirm_step "Setup Beads task management" && setup_beads
847
- confirm_step "Setup SEO integrations (curl subagents)" && setup_seo_mcps
848
- confirm_step "Setup Google Analytics MCP" && setup_google_analytics_mcp
849
- confirm_step "Setup QuickFile MCP (UK accounting)" && setup_quickfile_mcp
850
- confirm_step "Setup browser automation tools" && setup_browser_tools
851
- confirm_step "Setup AI orchestration frameworks info" && setup_ai_orchestration
852
- confirm_step "Setup Google Workspace CLI (Gmail, Calendar, Drive)" && setup_google_workspace_cli
853
- confirm_step "Setup OpenCode CLI (AI coding tool)" && setup_opencode_cli
854
- confirm_step "Setup OpenCode plugins" && setup_opencode_plugins
855
- # Run AFTER OpenCode CLI install so opencode.json may exist for agent config
856
- confirm_step "Update OpenCode configuration" && update_opencode_config
857
- # Run AFTER OpenCode config so Claude Code gets equivalent setup
858
- confirm_step "Update Claude Code configuration (slash commands, MCPs, settings)" && update_claude_config
859
- # Run AFTER all MCP setup functions to ensure disabled state persists
860
- confirm_step "Disable on-demand MCPs globally" && disable_ondemand_mcps
861
- fi
797
+ }
798
+ confirm_step "Setup Qlty CLI (multi-linter code quality)" && setup_qlty_cli
799
+ confirm_step "Rosetta audit (Apple Silicon x86 migration)" && setup_rosetta_audit
800
+ confirm_step "Setup Worktrunk (git worktree management)" && setup_worktrunk
801
+ confirm_step "Setup SSH key" && setup_ssh_key
802
+ confirm_step "Setup configuration files" && setup_configs
803
+ confirm_step "Set secure permissions on config files" && set_permissions
804
+ confirm_step "Install aidevops CLI command" && install_aidevops_cli
805
+ confirm_step "Setup shell aliases" && setup_aliases
806
+ confirm_step "Setup terminal title integration" && setup_terminal_title
807
+ confirm_step "Deploy AI templates to home directories" && deploy_ai_templates
808
+ confirm_step "Migrate old backups to new structure" && migrate_old_backups
809
+ confirm_step "Migrate loop state from .claude/.agent/ to .agents/loop-state/" && migrate_loop_state_directories
810
+ confirm_step "Migrate .agent -> .agents in user projects" && migrate_agent_to_agents_folder
811
+ confirm_step "Migrate mcp-env.sh -> credentials.sh" && migrate_mcp_env_to_credentials
812
+ confirm_step "Migrate pulse-repos.json into repos.json" && migrate_pulse_repos_to_repos_json
813
+ confirm_step "Cleanup deprecated agent paths" && cleanup_deprecated_paths
814
+ confirm_step "Migrate orphaned supervisor to pulse-wrapper" && migrate_orphaned_supervisor
815
+ confirm_step "Cleanup deprecated MCP entries (hetzner, serper, etc.)" && cleanup_deprecated_mcps
816
+ confirm_step "Cleanup stale bun opencode install" && cleanup_stale_bun_opencode
817
+ confirm_step "Validate and repair OpenCode config schema" && validate_opencode_config
818
+ confirm_step "Extract OpenCode prompts" && extract_opencode_prompts
819
+ confirm_step "Check OpenCode prompt drift" && check_opencode_prompt_drift
820
+ confirm_step "Deploy aidevops agents to ~/.aidevops/agents/" && deploy_aidevops_agents
821
+ confirm_step "Sync agents from private repositories" && sync_agent_sources
822
+ is_feature_enabled safety_hooks 2>/dev/null && confirm_step "Install Claude Code safety hooks (block destructive commands)" && setup_safety_hooks
823
+ confirm_step "Initialize settings.json (canonical config file)" && init_settings_json
824
+ confirm_step "Setup multi-tenant credential storage" && setup_multi_tenant_credentials
825
+ confirm_step "Generate agent skills (SKILL.md files)" && generate_agent_skills
826
+ confirm_step "Create symlinks for imported skills" && create_skill_symlinks
827
+ confirm_step "Check for skill updates from upstream" && check_skill_updates
828
+ confirm_step "Security scan imported skills" && scan_imported_skills
829
+ confirm_step "Inject agents reference into AI configs" && inject_agents_reference
830
+ confirm_step "Setup Python environment (DSPy, crawl4ai)" && setup_python_env
831
+ confirm_step "Setup Node.js environment" && setup_nodejs_env
832
+ confirm_step "Install MCP packages globally (fast startup)" && install_mcp_packages
833
+ confirm_step "Setup LocalWP MCP server" && setup_localwp_mcp
834
+ confirm_step "Setup Augment Context Engine MCP" && setup_augment_context_engine
835
+ confirm_step "Setup Beads task management" && setup_beads
836
+ confirm_step "Setup SEO integrations (curl subagents)" && setup_seo_mcps
837
+ confirm_step "Setup Google Analytics MCP" && setup_google_analytics_mcp
838
+ confirm_step "Setup QuickFile MCP (UK accounting)" && setup_quickfile_mcp
839
+ confirm_step "Setup browser automation tools" && setup_browser_tools
840
+ confirm_step "Setup AI orchestration frameworks info" && setup_ai_orchestration
841
+ confirm_step "Setup Google Workspace CLI (Gmail, Calendar, Drive)" && setup_google_workspace_cli
842
+ confirm_step "Setup OpenCode CLI (AI coding tool)" && setup_opencode_cli
843
+ confirm_step "Setup OpenCode plugins" && setup_opencode_plugins
844
+ confirm_step "Setup Codex CLI (OpenAI AI coding tool)" && setup_codex_cli
845
+ confirm_step "Setup Droid CLI (Factory.AI coding tool)" && setup_droid_cli
846
+ # Run AFTER CLI installs so config dirs may exist for agent config
847
+ confirm_step "Update OpenCode configuration" && update_opencode_config
848
+ # Run AFTER OpenCode config so Claude Code gets equivalent setup
849
+ confirm_step "Update Claude Code configuration (slash commands, MCPs, settings)" && update_claude_config
850
+ # Run AFTER Claude Code config so Codex/Cursor get equivalent setup
851
+ confirm_step "Update Codex configuration (MCPs, instructions)" && update_codex_config
852
+ confirm_step "Update Cursor configuration (MCPs)" && update_cursor_config
853
+ # Run AFTER all MCP setup functions to ensure disabled state persists
854
+ confirm_step "Disable on-demand MCPs globally" && disable_ondemand_mcps
855
+ return 0
856
+ }
857
+
858
+ # Post-setup steps: schedulers, final instructions, optional tool update check.
859
+ _setup_post_setup_steps() {
860
+ local os="$1"
862
861
 
863
862
  # Print setup summary before final success message (GH#5240)
864
863
  print_setup_summary
@@ -866,9 +865,15 @@ main() {
866
865
  echo ""
867
866
  print_success "Setup complete!"
868
867
 
868
+ # Non-interactive mode: deploy + migrations only — skip schedulers,
869
+ # services, and optional post-setup work (CI/agent shells don't need them).
870
+ if [[ "$NON_INTERACTIVE" == "true" ]]; then
871
+ return 0
872
+ fi
873
+
869
874
  # Post-setup: auto-update, schedulers, final instructions (GH#5793)
870
875
  setup_auto_update
871
- setup_supervisor_pulse "$_os"
876
+ setup_supervisor_pulse "$os"
872
877
  setup_stats_wrapper "${PULSE_ENABLED:-}"
873
878
  setup_repo_sync
874
879
  setup_process_guard
@@ -887,6 +892,39 @@ main() {
887
892
  fi
888
893
 
889
894
  setup_onboarding_prompt
895
+ return 0
896
+ }
897
+
898
+ # Main setup function — orchestrates init, mode dispatch, and post-setup.
899
+ main() {
900
+ # Bootstrap first (handles curl install)
901
+ bootstrap_repo "$@"
902
+
903
+ parse_args "$@"
904
+ local _os
905
+ _os="$(uname -s)"
906
+
907
+ # Auto-detect non-interactive terminals (CI/CD, agent shells, piped stdin)
908
+ # Must run after parse_args so explicit --interactive flag takes precedence
909
+ if [[ "$INTERACTIVE_MODE" != "true" && ! -t 0 ]]; then
910
+ NON_INTERACTIVE=true
911
+ fi
912
+
913
+ # Guard: --interactive and --non-interactive are mutually exclusive
914
+ if [[ "$INTERACTIVE_MODE" == "true" && "$NON_INTERACTIVE" == "true" ]]; then
915
+ print_error "--interactive and --non-interactive cannot be used together"
916
+ exit 1
917
+ fi
918
+
919
+ _setup_print_header
920
+
921
+ if [[ "$NON_INTERACTIVE" == "true" ]]; then
922
+ _setup_run_non_interactive
923
+ else
924
+ _setup_run_interactive
925
+ fi
926
+
927
+ _setup_post_setup_steps "$_os"
890
928
 
891
929
  return 0
892
930
  }