bmad-autopilot-addon 1.0.0

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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +279 -0
  3. package/_bmad-addons/.secrets-allowlist +26 -0
  4. package/_bmad-addons/BMAD.md +216 -0
  5. package/_bmad-addons/install.sh +495 -0
  6. package/_bmad-addons/manifest.yaml +22 -0
  7. package/_bmad-addons/modules/git/branching-and-pr-strategy.md +101 -0
  8. package/_bmad-addons/modules/git/config.yaml +83 -0
  9. package/_bmad-addons/modules/git/templates/commit-patch.txt +1 -0
  10. package/_bmad-addons/modules/git/templates/commit-story.txt +1 -0
  11. package/_bmad-addons/modules/git/templates/pr-body.md +20 -0
  12. package/_bmad-addons/modules/ma/config.yaml +9 -0
  13. package/_bmad-addons/scripts/create-pr.sh +198 -0
  14. package/_bmad-addons/scripts/detect-platform.sh +89 -0
  15. package/_bmad-addons/scripts/health-check.sh +107 -0
  16. package/_bmad-addons/scripts/lint-changed.sh +292 -0
  17. package/_bmad-addons/scripts/lock.sh +111 -0
  18. package/_bmad-addons/scripts/sanitize-branch.sh +83 -0
  19. package/_bmad-addons/scripts/stage-and-commit.sh +168 -0
  20. package/_bmad-addons/scripts/sync-status.sh +138 -0
  21. package/_bmad-addons/skills/bmad-autopilot-off/SKILL.md +6 -0
  22. package/_bmad-addons/skills/bmad-autopilot-off/workflow.md +154 -0
  23. package/_bmad-addons/skills/bmad-autopilot-on/SKILL.md +6 -0
  24. package/_bmad-addons/skills/bmad-autopilot-on/workflow.md +998 -0
  25. package/_bmad-addons/skills/bmad-ma-assess/SKILL.md +6 -0
  26. package/_bmad-addons/skills/bmad-ma-assess/agents/debt-classifier.md +64 -0
  27. package/_bmad-addons/skills/bmad-ma-assess/agents/dependency-auditor.md +57 -0
  28. package/_bmad-addons/skills/bmad-ma-assess/agents/migration-analyzer.md +62 -0
  29. package/_bmad-addons/skills/bmad-ma-assess/workflow.md +114 -0
  30. package/_bmad-addons/skills/bmad-ma-code-review/SKILL.md +6 -0
  31. package/_bmad-addons/skills/bmad-ma-code-review/agents/acceptance-auditor.md +51 -0
  32. package/_bmad-addons/skills/bmad-ma-code-review/agents/blind-hunter.md +39 -0
  33. package/_bmad-addons/skills/bmad-ma-code-review/agents/edge-case-hunter.md +46 -0
  34. package/_bmad-addons/skills/bmad-ma-code-review/workflow.md +111 -0
  35. package/_bmad-addons/skills/bmad-ma-codebase-map/SKILL.md +6 -0
  36. package/_bmad-addons/skills/bmad-ma-codebase-map/agents/architecture-mapper.md +129 -0
  37. package/_bmad-addons/skills/bmad-ma-codebase-map/agents/concerns-hunter.md +132 -0
  38. package/_bmad-addons/skills/bmad-ma-codebase-map/agents/integration-mapper.md +138 -0
  39. package/_bmad-addons/skills/bmad-ma-codebase-map/agents/quality-assessor.md +143 -0
  40. package/_bmad-addons/skills/bmad-ma-codebase-map/agents/stack-analyzer.md +123 -0
  41. package/_bmad-addons/skills/bmad-ma-codebase-map/workflow.md +120 -0
  42. package/_bmad-addons/skills/bmad-ma-migrate/SKILL.md +6 -0
  43. package/_bmad-addons/skills/bmad-ma-migrate/agents/dependency-analyzer.md +51 -0
  44. package/_bmad-addons/skills/bmad-ma-migrate/agents/risk-assessor.md +55 -0
  45. package/_bmad-addons/skills/bmad-ma-migrate/agents/stack-mapper.md +49 -0
  46. package/_bmad-addons/skills/bmad-ma-migrate/agents/test-parity-analyzer.md +49 -0
  47. package/_bmad-addons/skills/bmad-ma-migrate/resources/coexistence-patterns.md +59 -0
  48. package/_bmad-addons/skills/bmad-ma-migrate/resources/strategies.md +43 -0
  49. package/_bmad-addons/skills/bmad-ma-migrate/templates/component-card.md +11 -0
  50. package/_bmad-addons/skills/bmad-ma-migrate/templates/migration-epics.md +35 -0
  51. package/_bmad-addons/skills/bmad-ma-migrate/templates/migration-plan.md +66 -0
  52. package/_bmad-addons/skills/bmad-ma-migrate/workflow.md +235 -0
  53. package/_bmad-addons/skills/bmad-ma-party-mode/SKILL.md +6 -0
  54. package/_bmad-addons/skills/bmad-ma-party-mode/workflow.md +138 -0
  55. package/_bmad-addons/skills/bmad-ma-research/SKILL.md +6 -0
  56. package/_bmad-addons/skills/bmad-ma-research/workflow.md +128 -0
  57. package/_bmad-addons/skills/bmad-ma-reverse-architect/SKILL.md +6 -0
  58. package/_bmad-addons/skills/bmad-ma-reverse-architect/agents/component-mapper.md +53 -0
  59. package/_bmad-addons/skills/bmad-ma-reverse-architect/agents/data-flow-tracer.md +54 -0
  60. package/_bmad-addons/skills/bmad-ma-reverse-architect/agents/pattern-extractor.md +67 -0
  61. package/_bmad-addons/skills/bmad-ma-reverse-architect/workflow.md +119 -0
  62. package/_bmad-addons/templates/agent-rules.md +43 -0
  63. package/_bmad-addons/uninstall.sh +204 -0
  64. package/bin/bmad-autopilot-addon.sh +48 -0
  65. package/package.json +32 -0
@@ -0,0 +1,495 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ ADDON_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ PROJECT_ROOT="${BMAD_PROJECT_ROOT:-$(dirname "$ADDON_DIR")}"
6
+ MANIFEST="$PROJECT_ROOT/_bmad/_config/manifest.yaml"
7
+ ADDON_MANIFEST="$ADDON_DIR/manifest.yaml"
8
+ MAX_BACKUPS=3
9
+ DRY_RUN=false
10
+ FORCE=false
11
+ TOOLS=""
12
+ YES=false
13
+
14
+ # --- Supported tools and their base directories ---
15
+ # Skills go to {base_dir}/skills/
16
+ # Compatible with Bash 3.2+ (no associative arrays)
17
+ get_tool_dir() {
18
+ case "$1" in
19
+ claude-code) echo ".claude" ;;
20
+ cursor) echo ".cursor" ;;
21
+ windsurf) echo ".windsurf" ;;
22
+ cline) echo ".cline" ;;
23
+ roo) echo ".roo" ;;
24
+ trae) echo ".trae" ;;
25
+ kiro) echo ".kiro" ;;
26
+ github-copilot) echo ".github/copilot" ;;
27
+ gemini-cli) echo ".gemini" ;;
28
+ *) echo "" ;;
29
+ esac
30
+ }
31
+
32
+ ALL_TOOLS="claude-code cursor windsurf gemini-cli cline roo trae kiro github-copilot"
33
+
34
+ # System prompt file per tool (for BMAD workflow enforcement)
35
+ get_system_prompt_file() {
36
+ case "$1" in
37
+ claude-code) echo "AGENTS.md" ;;
38
+ cursor) echo ".cursor/rules/bmad.md" ;;
39
+ windsurf) echo ".windsurfrules" ;;
40
+ cline) echo ".clinerules" ;;
41
+ roo) echo ".roo/rules/bmad.md" ;;
42
+ gemini-cli) echo "GEMINI.md" ;;
43
+ github-copilot) echo ".github/copilot-instructions.md" ;;
44
+ kiro) echo ".kiro/rules/bmad.md" ;;
45
+ trae) echo ".trae/rules/bmad.md" ;;
46
+ *) echo "" ;;
47
+ esac
48
+ }
49
+
50
+ # "claude-code" = special CLAUDE.md + AGENTS.md pattern
51
+ # "own-file" = tool has rules directory, BMAD gets its own file (overwrite ok)
52
+ # "append" = shared file, use marker-based append/replace
53
+ get_system_prompt_mode() {
54
+ case "$1" in
55
+ claude-code) echo "claude-code" ;;
56
+ cursor|roo|kiro|trae) echo "own-file" ;;
57
+ windsurf|cline|gemini-cli|github-copilot) echo "append" ;;
58
+ *) echo "" ;;
59
+ esac
60
+ }
61
+
62
+ # Install system prompt for a tool (marker-based, idempotent)
63
+ install_system_prompt() {
64
+ local tool="$1"
65
+ local mode
66
+ mode=$(get_system_prompt_mode "$tool")
67
+ local rules_content
68
+ rules_content=$(cat "$ADDON_DIR/templates/agent-rules.md")
69
+ local prompt_file="$PROJECT_ROOT/$(get_system_prompt_file "$tool")"
70
+
71
+ if [ "$DRY_RUN" = true ]; then
72
+ echo " [DRY RUN] Would install system prompt for $tool ($mode)"
73
+ return
74
+ fi
75
+
76
+ case "$mode" in
77
+ claude-code)
78
+ # 1. AGENTS.md: marker-based append/replace
79
+ local agents_file="$PROJECT_ROOT/AGENTS.md"
80
+ if [ -f "$agents_file" ] && grep -q '<!-- BEGIN:bmad-workflow-rules -->' "$agents_file" 2>/dev/null; then
81
+ # Replace existing BMAD section
82
+ local tmp
83
+ tmp=$(mktemp "${prompt_file}.XXXXXX" 2>/dev/null || mktemp)
84
+ awk '/<!-- BEGIN:bmad-workflow-rules -->/{skip=1; next} /<!-- END:bmad-workflow-rules -->/{skip=0; next} !skip{print}' "$agents_file" > "$tmp"
85
+ printf '\n%s\n' "$rules_content" >> "$tmp"
86
+ mv "$tmp" "$agents_file"
87
+ echo " System prompt: AGENTS.md (updated BMAD section)"
88
+ elif [ -f "$agents_file" ]; then
89
+ # Append to existing
90
+ printf '\n%s\n' "$rules_content" >> "$agents_file"
91
+ echo " System prompt: AGENTS.md (appended BMAD section)"
92
+ else
93
+ # Create new
94
+ printf '%s\n' "$rules_content" > "$agents_file"
95
+ echo " System prompt: AGENTS.md (created)"
96
+ fi
97
+
98
+ # 2. CLAUDE.md: ensure @AGENTS.md line exists
99
+ local claude_file="$PROJECT_ROOT/CLAUDE.md"
100
+ if [ -f "$claude_file" ] && grep -q '@AGENTS.md' "$claude_file" 2>/dev/null; then
101
+ echo " System prompt: CLAUDE.md (already has @AGENTS.md)"
102
+ elif [ -f "$claude_file" ]; then
103
+ printf '\n@AGENTS.md\n' >> "$claude_file"
104
+ echo " System prompt: CLAUDE.md (appended @AGENTS.md)"
105
+ else
106
+ printf '@AGENTS.md\n' > "$claude_file"
107
+ echo " System prompt: CLAUDE.md (created with @AGENTS.md)"
108
+ fi
109
+ ;;
110
+
111
+ own-file)
112
+ # Write directly — this file is fully owned by the addon
113
+ local dir
114
+ dir=$(dirname "$prompt_file")
115
+ mkdir -p "$dir"
116
+ printf '%s\n' "$rules_content" > "$prompt_file"
117
+ echo " System prompt: $(get_system_prompt_file "$tool") (created)"
118
+ ;;
119
+
120
+ append)
121
+ # Marker-based append/replace in shared file
122
+ if [ -f "$prompt_file" ] && grep -q '<!-- BEGIN:bmad-workflow-rules -->' "$prompt_file" 2>/dev/null; then
123
+ local tmp
124
+ tmp=$(mktemp "${prompt_file}.XXXXXX" 2>/dev/null || mktemp)
125
+ awk '/<!-- BEGIN:bmad-workflow-rules -->/{skip=1; next} /<!-- END:bmad-workflow-rules -->/{skip=0; next} !skip{print}' "$prompt_file" > "$tmp"
126
+ printf '\n%s\n' "$rules_content" >> "$tmp"
127
+ mv "$tmp" "$prompt_file"
128
+ echo " System prompt: $(get_system_prompt_file "$tool") (updated BMAD section)"
129
+ elif [ -f "$prompt_file" ]; then
130
+ printf '\n%s\n' "$rules_content" >> "$prompt_file"
131
+ echo " System prompt: $(get_system_prompt_file "$tool") (appended BMAD section)"
132
+ else
133
+ local dir
134
+ dir=$(dirname "$prompt_file")
135
+ mkdir -p "$dir"
136
+ printf '%s\n' "$rules_content" > "$prompt_file"
137
+ echo " System prompt: $(get_system_prompt_file "$tool") (created)"
138
+ fi
139
+ ;;
140
+ esac
141
+ }
142
+
143
+ # --- Parse flags ---
144
+ while [ "$#" -gt 0 ]; do
145
+ case $1 in
146
+ --tools) TOOLS="$2"; shift ;;
147
+ --dry-run) DRY_RUN=true ;;
148
+ --force) FORCE=true ;;
149
+ --yes|-y) YES=true ;;
150
+ -h|--help)
151
+ cat <<'HELPEOF'
152
+ BMAD Autopilot Add-On Installer
153
+
154
+ Usage: install.sh [OPTIONS]
155
+
156
+ Options:
157
+ --tools <list> Comma-separated list of target tools (e.g., claude-code,cursor)
158
+ --dry-run Show what would be done without making changes
159
+ --force Skip backup of existing skills before overwrite
160
+ --yes, -y Non-interactive mode (use detected/specified tools without prompting)
161
+ -h, --help Show this help
162
+
163
+ Supported tools:
164
+ claude-code Claude Code CLI, desktop, web, IDE extensions
165
+ cursor Cursor IDE
166
+ windsurf Windsurf IDE
167
+ cline Cline (VS Code extension)
168
+ roo Roo Code (VS Code extension)
169
+ trae Trae IDE
170
+ kiro Kiro IDE
171
+ gemini-cli Gemini CLI (Google)
172
+ github-copilot GitHub Copilot
173
+
174
+ Examples:
175
+ install.sh # Interactive tool selection
176
+ install.sh --tools claude-code # Install for Claude Code only
177
+ install.sh --tools claude-code,cursor # Install for multiple tools
178
+ install.sh --tools all # Install for all supported tools
179
+ install.sh --tools all --yes # Non-interactive, all tools
180
+ install.sh --dry-run --tools cursor # Preview Cursor installation
181
+ HELPEOF
182
+ exit 0
183
+ ;;
184
+ *) echo "Unknown option: $1. Use --help for usage."; exit 1 ;;
185
+ esac
186
+ shift
187
+ done
188
+
189
+ ADDON_VERSION=$(grep 'version:' "$ADDON_MANIFEST" | head -1 | awk '{print $2}')
190
+ cat << BANNER
191
+ ____ __ __ _ ____ _ _ _ _ _
192
+ | __ )| \/ | / \ | _ \ / \ _ _| |_ ___ _ __ (_) | ___ | |_
193
+ | _ \| |\/| | / _ \ | | | | / _ \| | | | __/ _ \| '_ \| | |/ _ \| __|
194
+ | |_) | | | |/ ___ \| |_| | / ___ \ |_| | || (_) | |_) | | | (_) | |_
195
+ |____/|_| |_/_/ \_\____/ /_/ \_\__,_|\__\___/| .__/|_|_|\___/ \__| v$ADDON_VERSION
196
+ |_|
197
+ BANNER
198
+ echo ""
199
+
200
+ # --- 1. Verify BMAD is installed ---
201
+ if [ ! -f "$MANIFEST" ]; then
202
+ echo "ERROR: BMAD not found at $PROJECT_ROOT"
203
+ echo "Install BMAD first: npx bmad-method install"
204
+ exit 1
205
+ fi
206
+
207
+ BMAD_VERSION=$(grep 'version:' "$MANIFEST" | head -1 | awk '{print $2}')
208
+ echo "BMAD version: $BMAD_VERSION"
209
+ echo ""
210
+
211
+ # --- 2. Detect or select tools ---
212
+
213
+ # Auto-detect which tools have BMAD installed (have a skills directory)
214
+ detect_installed_tools() {
215
+ local detected=""
216
+ for tool in $ALL_TOOLS; do
217
+ local dir
218
+ dir=$(get_tool_dir "$tool")
219
+ if [ -d "$PROJECT_ROOT/$dir/skills" ]; then
220
+ if [ -n "$detected" ]; then
221
+ detected="$detected,$tool"
222
+ else
223
+ detected="$tool"
224
+ fi
225
+ fi
226
+ done
227
+ echo "$detected"
228
+ }
229
+
230
+ DETECTED_TOOLS=$(detect_installed_tools)
231
+
232
+ if [ "$TOOLS" = "all" ]; then
233
+ TOOLS=$(echo "$ALL_TOOLS" | tr ' ' ',')
234
+ elif [ -z "$TOOLS" ]; then
235
+ if [ "$YES" = true ]; then
236
+ # Non-interactive: use detected tools
237
+ if [ -n "$DETECTED_TOOLS" ]; then
238
+ TOOLS="$DETECTED_TOOLS"
239
+ echo "Auto-detected tools: $TOOLS"
240
+ else
241
+ echo "ERROR: No tools detected. Specify with --tools" >&2
242
+ exit 1
243
+ fi
244
+ else
245
+ # Interactive tool selection
246
+ echo "Select target tools for add-on installation."
247
+ echo "Skills will be installed to each tool's skills directory."
248
+ echo ""
249
+ if [ -n "$DETECTED_TOOLS" ]; then
250
+ echo "Detected (BMAD already installed for these):"
251
+ OLD_IFS="$IFS"; IFS=','
252
+ for t in $DETECTED_TOOLS; do
253
+ echo " * $t -> $(get_tool_dir "$t")/skills/"
254
+ done
255
+ IFS="$OLD_IFS"
256
+ echo ""
257
+ fi
258
+ echo "Available tools:"
259
+ i=1
260
+ TOOL_BY_NUM=""
261
+ for tool in $ALL_TOOLS; do
262
+ dir=$(get_tool_dir "$tool")
263
+ marker=""
264
+ case ",$DETECTED_TOOLS," in
265
+ *",$tool,"*) marker=" [detected]" ;;
266
+ esac
267
+ echo " $i) $tool -> $dir/skills/$marker"
268
+ TOOL_BY_NUM="$TOOL_BY_NUM $i:$tool"
269
+ i=$((i + 1))
270
+ done
271
+ echo ""
272
+ echo "Enter tool numbers (comma-separated), tool names, or 'all':"
273
+ echo " Example: 1,2 or claude-code,cursor or all"
274
+ if [ -n "$DETECTED_TOOLS" ]; then
275
+ echo " Press Enter to use detected tools: $DETECTED_TOOLS"
276
+ fi
277
+ read -r SELECTION
278
+
279
+ if [ -z "$SELECTION" ] && [ -n "$DETECTED_TOOLS" ]; then
280
+ TOOLS="$DETECTED_TOOLS"
281
+ elif [ "$SELECTION" = "all" ]; then
282
+ TOOLS=$(echo "$ALL_TOOLS" | tr ' ' ',')
283
+ else
284
+ # Parse selection (numbers or names)
285
+ TOOLS=""
286
+ OLD_IFS="$IFS"; IFS=','
287
+ for item in $SELECTION; do
288
+ item=$(echo "$item" | tr -d ' ')
289
+ IFS="$OLD_IFS"
290
+ # Check if numeric
291
+ case "$item" in
292
+ [0-9]|[0-9][0-9])
293
+ # Find tool by number
294
+ selected=$(echo "$TOOL_BY_NUM" | tr ' ' '\n' | grep "^$item:" | cut -d: -f2)
295
+ if [ -n "$selected" ]; then
296
+ [ -n "$TOOLS" ] && TOOLS="$TOOLS,"
297
+ TOOLS="${TOOLS}${selected}"
298
+ else
299
+ echo "WARNING: invalid number $item, skipping"
300
+ fi
301
+ ;;
302
+ *)
303
+ # Validate tool name
304
+ dir=$(get_tool_dir "$item")
305
+ if [ -n "$dir" ]; then
306
+ [ -n "$TOOLS" ] && TOOLS="$TOOLS,"
307
+ TOOLS="${TOOLS}${item}"
308
+ else
309
+ echo "WARNING: unknown tool '$item', skipping"
310
+ fi
311
+ ;;
312
+ esac
313
+ IFS=','
314
+ done
315
+ IFS="$OLD_IFS"
316
+ fi
317
+ fi
318
+ fi
319
+
320
+ if [ -z "$TOOLS" ]; then
321
+ echo "ERROR: No tools selected." >&2
322
+ exit 1
323
+ fi
324
+
325
+ # Split tools into array-like variable
326
+ SELECTED_TOOLS=$(echo "$TOOLS" | tr ',' ' ')
327
+ TOOL_COUNT=$(echo "$SELECTED_TOOLS" | wc -w | tr -d ' ')
328
+
329
+ echo ""
330
+ echo "Installing for: $SELECTED_TOOLS"
331
+ echo ""
332
+
333
+ # --- 3. Ensure .gitignore covers addon artifacts ---
334
+ add_ignore_entry() {
335
+ local entry="$1"
336
+ local target_file="$2"
337
+
338
+ if [ -f "$target_file" ]; then
339
+ if ! grep -qF "$entry" "$target_file" 2>/dev/null; then
340
+ if [ "$DRY_RUN" = true ]; then
341
+ echo "[DRY RUN] Would add '$entry' to $(basename "$target_file")"
342
+ else
343
+ echo "$entry" >> "$target_file"
344
+ echo "Added '$entry' to $(basename "$target_file")"
345
+ fi
346
+ fi
347
+ else
348
+ if [ "$DRY_RUN" = true ]; then
349
+ echo "[DRY RUN] Would create $(basename "$target_file") with '$entry'"
350
+ else
351
+ echo "$entry" > "$target_file"
352
+ echo "Created $(basename "$target_file") with '$entry'"
353
+ fi
354
+ fi
355
+ }
356
+
357
+ IGNORE_FILE="$PROJECT_ROOT/.gitignore"
358
+ if [ ! -f "$IGNORE_FILE" ]; then
359
+ EXCLUDE_FILE="$PROJECT_ROOT/.git/info/exclude"
360
+ if [ -f "$EXCLUDE_FILE" ] && [ -s "$EXCLUDE_FILE" ]; then
361
+ IGNORE_FILE="$EXCLUDE_FILE"
362
+ echo "Using .git/info/exclude (no .gitignore found)"
363
+ fi
364
+ fi
365
+
366
+ add_ignore_entry ".autopilot.lock" "$IGNORE_FILE"
367
+
368
+ # --- 4. Install skills to each selected tool ---
369
+ TOTAL_INSTALLED=0
370
+ SKILL_COUNT=$(ls -d "$ADDON_DIR/skills"/*/ 2>/dev/null | wc -l | tr -d ' ')
371
+
372
+ for tool in $SELECTED_TOOLS; do
373
+ TOOL_DIR=$(get_tool_dir "$tool")
374
+
375
+ if [ -z "$TOOL_DIR" ]; then
376
+ echo "WARNING: Unknown tool '$tool', skipping"
377
+ continue
378
+ fi
379
+
380
+ SKILLS_DIR="$PROJECT_ROOT/$TOOL_DIR/skills"
381
+ BACKUP_DIR="$PROJECT_ROOT/$TOOL_DIR/.addon-backups"
382
+
383
+ # Add backup dir to gitignore
384
+ add_ignore_entry "$TOOL_DIR/.addon-backups/" "$IGNORE_FILE"
385
+
386
+ echo "--- $tool -> $TOOL_DIR/skills/ ---"
387
+
388
+ # Create skills directory if it doesn't exist
389
+ if [ ! -d "$SKILLS_DIR" ]; then
390
+ if [ "$DRY_RUN" = true ]; then
391
+ echo " [DRY RUN] Would create $SKILLS_DIR"
392
+ else
393
+ mkdir -p "$SKILLS_DIR"
394
+ echo " Created: $SKILLS_DIR"
395
+ fi
396
+ fi
397
+
398
+ # Create backup directory
399
+ if [ "$DRY_RUN" = false ]; then
400
+ mkdir -p "$BACKUP_DIR" 2>/dev/null || true
401
+ fi
402
+ BACKUP_TS="$(date +%Y%m%d%H%M%S)"
403
+
404
+ TOOL_INSTALLED=0
405
+ for skill in "$ADDON_DIR/skills"/*/; do
406
+ [ -d "$skill" ] || continue
407
+ skill_name=$(basename "$skill")
408
+ target="$SKILLS_DIR/$skill_name"
409
+
410
+ # Backup existing skill if present
411
+ if [ -d "$target" ] && [ "$FORCE" = false ]; then
412
+ backup="$BACKUP_DIR/${skill_name}.${BACKUP_TS}"
413
+ if [ "$DRY_RUN" = true ]; then
414
+ echo " [DRY RUN] Would backup $skill_name"
415
+ else
416
+ cp -r "$target" "$backup"
417
+ fi
418
+ fi
419
+
420
+ # Install skill
421
+ if [ "$DRY_RUN" = true ]; then
422
+ echo " [DRY RUN] Would install $skill_name"
423
+ else
424
+ rm -rf "$target"
425
+ cp -r "$skill" "$target/"
426
+ TOOL_INSTALLED=$((TOOL_INSTALLED + 1))
427
+ fi
428
+ done
429
+
430
+ # Prune old backups (keep MAX_BACKUPS per skill)
431
+ if [ "$DRY_RUN" = false ] && [ -d "$BACKUP_DIR" ]; then
432
+ for skill in "$ADDON_DIR/skills"/*/; do
433
+ [ -d "$skill" ] || continue
434
+ skill_name=$(basename "$skill")
435
+ count=0
436
+ remove_list=""
437
+ for backup in $(ls -d "$BACKUP_DIR/${skill_name}."* 2>/dev/null | sort); do
438
+ count=$((count + 1))
439
+ done
440
+ if [ "$count" -gt "$MAX_BACKUPS" ]; then
441
+ remove=$((count - MAX_BACKUPS))
442
+ removed=0
443
+ for backup in $(ls -d "$BACKUP_DIR/${skill_name}."* 2>/dev/null | sort); do
444
+ if [ "$removed" -lt "$remove" ]; then
445
+ rm -rf "$backup"
446
+ removed=$((removed + 1))
447
+ fi
448
+ done
449
+ fi
450
+ done
451
+ fi
452
+
453
+ if [ "$DRY_RUN" = false ]; then
454
+ echo " Installed $TOOL_INSTALLED skills"
455
+ TOTAL_INSTALLED=$((TOTAL_INSTALLED + TOOL_INSTALLED))
456
+ fi
457
+
458
+ # Install system prompt for BMAD workflow enforcement
459
+ install_system_prompt "$tool"
460
+
461
+ echo ""
462
+ done
463
+
464
+ # Verify ignore is effective
465
+ if [ "$DRY_RUN" = false ] && command -v git >/dev/null 2>&1 && [ -d "$PROJECT_ROOT/.git" ]; then
466
+ if ! git -C "$PROJECT_ROOT" check-ignore -q .autopilot.lock 2>/dev/null; then
467
+ echo "WARNING: .autopilot.lock may not be effectively ignored by git"
468
+ fi
469
+ fi
470
+
471
+ # --- 5. Report ---
472
+ echo ""
473
+ if [ "$DRY_RUN" = true ]; then
474
+ echo "Dry run complete. No changes made."
475
+ else
476
+ echo "=== Add-on v$ADDON_VERSION installed ==="
477
+ echo ""
478
+ echo "Tools configured: $SELECTED_TOOLS"
479
+ echo "Total skills installed: $TOTAL_INSTALLED ($SKILL_COUNT skills x $TOOL_COUNT tools)"
480
+ echo ""
481
+ echo "Skills:"
482
+ for skill in "$ADDON_DIR/skills"/*/; do
483
+ [ -d "$skill" ] || continue
484
+ echo " - $(basename "$skill")"
485
+ done
486
+ echo ""
487
+ echo "Locations:"
488
+ for tool in $SELECTED_TOOLS; do
489
+ echo " $tool -> $(get_tool_dir "$tool")/skills/"
490
+ done
491
+ echo ""
492
+ echo "Backups: kept in each tool's .addon-backups/ (last $MAX_BACKUPS per skill)"
493
+ echo ""
494
+ echo "Next: invoke /bmad-autopilot-on in your IDE to start using git workflow."
495
+ fi
@@ -0,0 +1,22 @@
1
+ addon:
2
+ name: bmad-ma-git
3
+ version: 1.0.0
4
+ description: Multi-agent execution + git workflow integration for BMAD
5
+ bmad_compatibility: ">=6.2.0"
6
+ modules:
7
+ git:
8
+ enabled: true
9
+ config: modules/git/config.yaml
10
+ ma:
11
+ enabled: true
12
+ config: modules/ma/config.yaml
13
+ installed_skills:
14
+ - bmad-autopilot-on
15
+ - bmad-autopilot-off
16
+ - bmad-ma-code-review
17
+ - bmad-ma-codebase-map
18
+ - bmad-ma-assess
19
+ - bmad-ma-reverse-architect
20
+ - bmad-ma-migrate
21
+ - bmad-ma-research
22
+ - bmad-ma-party-mode
@@ -0,0 +1,101 @@
1
+ # Git Branching and PR Strategy
2
+
3
+ How the BMAD autopilot addon manages branches, PRs, and merging across stories.
4
+
5
+ ## Configuration
6
+
7
+ Controlled by `git.push.create_pr` in `modules/git/config.yaml`:
8
+
9
+ ```yaml
10
+ git:
11
+ push:
12
+ create_pr: true # PR flow — create PR, no auto-merge, wait for approval
13
+ create_pr: false # Direct merge — merge story branch to main after push
14
+ ```
15
+
16
+ ## Branch Naming
17
+
18
+ Each story gets a branch: `story/{story-key}` (e.g., `story/1-2-user-authentication`).
19
+
20
+ The story key is derived from `sprint-status.yaml`. If the key is numeric-only (e.g., `1-2`), the autopilot enriches it from the story file or epics file to produce a human-readable branch name.
21
+
22
+ Branch names are sanitized (lowercased, special chars removed) and truncated to 60 characters with a hash suffix if longer.
23
+
24
+ ## Direct Merge Flow (`create_pr: false`)
25
+
26
+ ```
27
+ main ─── story/1-1 ──→ merge to main ─── story/1-2 ──→ merge to main
28
+ ```
29
+
30
+ Each story:
31
+ 1. Branches from `origin/main`
32
+ 2. Code is developed in a worktree
33
+ 3. Branch is pushed to origin
34
+ 4. Branch is merged directly to main: `git merge story/1-1 --no-edit`
35
+ 5. Main is pushed to origin
36
+
37
+ The next story always branches from the updated main.
38
+
39
+ ## PR Flow (`create_pr: true`)
40
+
41
+ When PRs are enabled, stories are **never auto-merged**. The branch is pushed and a PR is created. Merging happens through the platform's PR review process.
42
+
43
+ ### Single story (or first story in epic)
44
+
45
+ ```
46
+ main ─── story/1-1 ──→ push + PR (story/1-1 → main)
47
+ ```
48
+
49
+ 1. Branches from `origin/main`
50
+ 2. Code is developed in a worktree
51
+ 3. Branch is pushed to origin
52
+ 4. PR is created targeting `main`
53
+ 5. No merge — PR awaits approval
54
+
55
+ ### Stacked stories (subsequent stories, previous PR pending)
56
+
57
+ ```
58
+ main ─── story/1-1 ──→ PR (→ main)
59
+ └── story/1-2 ──→ PR (→ story/1-1)
60
+ └── story/1-3 ──→ PR (→ story/1-2)
61
+ ```
62
+
63
+ When the previous story's PR is not yet merged:
64
+ 1. The autopilot detects the unmerged branch via `git-status.yaml` and `git merge-base --is-ancestor`
65
+ 2. New story branches from `origin/story/<previous-story>` instead of main
66
+ 3. PR targets the previous story branch (not main)
67
+ 4. This creates a stacked PR chain
68
+
69
+ ### After PR merge (between sessions)
70
+
71
+ When story/1-1's PR is merged on the platform before the next session:
72
+ 1. `git merge-base --is-ancestor origin/story/1-1 origin/main` returns true
73
+ 2. The autopilot detects that 1-1 is now on main
74
+ 3. Story/1-2 branches from `origin/main` (which includes 1-1's code)
75
+ 4. PR targets `main`
76
+
77
+ GitHub, GitLab, and Bitbucket automatically retarget stacked PRs when the base is merged.
78
+
79
+ ## Decision Matrix
80
+
81
+ | Config | Previous story | Branch source | PR target | Post-push action |
82
+ |--------|---------------|---------------|-----------|-----------------|
83
+ | `create_pr: false` | Any | `origin/main` | N/A | Merge to main |
84
+ | `create_pr: true` | None or merged | `origin/main` | `main` | PR created, no merge |
85
+ | `create_pr: true` | Unmerged (PR pending) | `origin/story/<prev>` | `story/<prev>` | PR created, no merge |
86
+
87
+ ## Session Persistence
88
+
89
+ The PR target branch (`pr_base`) is saved in `autopilot-state.yaml` and restored on session resume. This ensures that a resumed session creates PRs against the correct base branch even if it was a stacked story.
90
+
91
+ ## Artifacts on Main
92
+
93
+ Regardless of the merge strategy, implementation artifacts (sprint-status.yaml, git-status.yaml, story files, planning documents) are always committed and pushed to main after each story completes. This ensures main reflects the current sprint state even when story code is on PR branches.
94
+
95
+ ## File Ownership
96
+
97
+ | File | Owner | Autopilot access |
98
+ |------|-------|-----------------|
99
+ | `sprint-status.yaml` | BMAD (dev-story, sprint-planning, retrospective) | Read only |
100
+ | `git-status.yaml` | Autopilot addon | Read/write |
101
+ | `autopilot-state.yaml` | Autopilot addon | Read/write |
@@ -0,0 +1,83 @@
1
+ # Git Workflow Configuration for BMAD Autopilot Add-On
2
+ # Worktrees are managed via standard git commands at .worktrees/{name}
3
+
4
+ git:
5
+ enabled: true # false = all git ops silently skip
6
+ base_branch: main
7
+ # Git status is tracked in git-status.yaml (addon-owned), NOT sprint-status.yaml (BMAD-owned)
8
+
9
+ # Branch naming
10
+ branch_prefix: "story/" # prefix for story branches (e.g., story/1-2-user-auth)
11
+ max_branch_length: 60 # truncate + 6-char hash if longer
12
+
13
+ # Commit message templates
14
+ # Placeholders: {story-key}, {epic}, {story-title}, {patch-title}
15
+ commit_templates:
16
+ story: "feat({epic}): {story-title} ({story-key})"
17
+ patch: "fix({story-key}): {patch-title}"
18
+
19
+ # Placeholder resolution chain: sprint-status.yaml -> story file -> fallback
20
+ commit_placeholder_resolution:
21
+ story-key: "from sprint-status.yaml development_status key"
22
+ epic: "from story file epic header, fallback to story-key prefix (e.g., '1' from '1-3')"
23
+ story-title: "from story file title, fallback to story-key"
24
+ patch-title: "from review finding title, fallback to 'code review fix'"
25
+
26
+ # Linting
27
+ lint:
28
+ enabled: true
29
+ blocking: false # true = lint errors halt the autopilot; false = warn only
30
+ output_limit: 100 # max lines of lint output injected into context
31
+ # Linter preference per language — first found wins.
32
+ # Override to force a specific tool (e.g., set typescript: [biome] to skip eslint).
33
+ linters:
34
+ python: [ruff, flake8, pylint]
35
+ javascript: [eslint, biome]
36
+ typescript: [eslint, biome]
37
+ rust: [cargo clippy]
38
+ go: [golangci-lint]
39
+ ruby: [rubocop]
40
+ java: [checkstyle, pmd]
41
+ c: [cppcheck, clang-tidy]
42
+ cpp: [cppcheck, clang-tidy]
43
+ csharp: [dotnet format]
44
+ swift: [swiftlint]
45
+ plsql: [sqlfluff]
46
+ kotlin: [ktlint, detekt]
47
+ php: [phpstan, phpcs]
48
+ # To add a new language: add an entry here and a matching block in scripts/lint-changed.sh
49
+
50
+ # Push & PR
51
+ push:
52
+ auto: true # false = branches stay local, no push or PR
53
+ create_pr: true # true = create PR and wait for approval (no auto-merge)
54
+ # false = merge directly to base branch after push
55
+ pr_template: "modules/git/templates/pr-body.md" # relative to _bmad-addons/
56
+
57
+ # Worktree settings (location: .worktrees/ in project root)
58
+ worktree:
59
+ submodule_init: auto # auto = only if .gitmodules exists
60
+ submodule_timeout: 30 # seconds
61
+ cleanup_on_merge: true # false = keep worktrees after epic completion for inspection
62
+ health_check_on_boot: true # check for orphaned worktrees from crashed sessions
63
+
64
+ # Lock file (.autopilot.lock — prevents concurrent autopilot sessions)
65
+ lock:
66
+ stale_timeout_minutes: 30 # auto-remove locks older than this
67
+
68
+ # Platform detection
69
+ platform:
70
+ provider: auto # auto | github | gitlab | bitbucket | gitea | git_only
71
+ # Detection priority:
72
+ # 1. Explicit provider in this config (if not "auto")
73
+ # 2. CLI detection: which CLIs are installed (gh, glab, bb, tea)
74
+ # 3. Remote URL regex as last resort
75
+ #
76
+ # For self-hosted Gitea:
77
+ # provider: gitea
78
+ # base_url: https://git.example.com
79
+ # # Set GITEA_TOKEN env var for API auth
80
+ #
81
+ # For Bitbucket Server:
82
+ # provider: bitbucket
83
+ # # Set BITBUCKET_TOKEN env var for API auth