#!/usr/bin/env bash # post-bmad-install.sh # À lancer après `npx bmad-method install` dans un projet BMAD. # Injecte la memory de capitalisation Lead_tech dans les agents producteurs. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" TEMPLATES_DIR="$SCRIPT_DIR/../70_templates/bmad_post_install" # Projet courant PROJECT_ROOT="$(pwd)" PROJECT_NAME="$(basename "$PROJECT_ROOT")" AGENTS_DIR="$PROJECT_ROOT/_bmad/_config/agents" CLAUDE_MD="$PROJECT_ROOT/CLAUDE.md" DEV_STORY_XML="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/dev-story/instructions.xml" CODE_REVIEW_XML="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/code-review/instructions.xml" DEV_STORY_CHECKLIST="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/dev-story/checklist.md" CODE_REVIEW_CHECKLIST="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/code-review/checklist.md" STORY_TEMPLATE_MD="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/create-story/template.md" CREATE_STORY_XML="$PROJECT_ROOT/_bmad/bmm/workflows/4-implementation/create-story/instructions.xml" PRODUCER_AGENTS_CONFIG="$TEMPLATES_DIR/config/producer_agents.tsv" MEMORIES_DIR="$TEMPLATES_DIR/memories" WORKFLOWS_DIR="$TEMPLATES_DIR/workflows" CLAUDE_FRAGMENTS_DIR="$TEMPLATES_DIR/claude" CAPITALIZE_MARKER="95_a_capitaliser.md" CAPITALIZE_MARKER_XML="Capitalisation Lead_tech" PARALLELIZATION_MARKER_XML="Story parallelization check" CREATE_STORY_PARALLELIZATION_MARKER_XML="Story parallelization metadata" if [ ! -d "$AGENTS_DIR" ]; then echo "Erreur : dossier _bmad/_config/agents/ introuvable dans $PROJECT_ROOT" >&2 echo "Lance ce script depuis la racine d'un projet BMAD installé." >&2 exit 1 fi require_file() { local file="$1" if [ ! -f "$file" ]; then echo "Erreur : fichier requis introuvable : $file" >&2 exit 1 fi } escape_sed_replacement() { printf '%s' "$1" | sed -e 's/[\/&]/\\&/g' } render_template() { local file="$1" require_file "$file" sed "s/__PROJECT_NAME__/$(escape_sed_replacement "$PROJECT_NAME")/g" "$file" } render_template_to_temp_file() { local file="$1" local output output="$(mktemp)" render_template "$file" > "$output" printf '%s\n' "$output" } patch_line_after_match() { local file="$1" local match="$2" local fragment_file="$3" if [ ! -f "$file" ]; then echo " [skip] $(basename "$file") — fichier absent" return 0 fi if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then echo " [skip] $(basename "$file") — capitalisation déjà présente" return 0 fi local rendered_fragment rendered_fragment="$(render_template_to_temp_file "$fragment_file")" awk -v match="$match" -v fragfile="$rendered_fragment" ' index($0, match) { print while ((getline line < fragfile) > 0) print line close(fragfile) next } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" rm -f "$rendered_fragment" echo " [ok] $(basename "$file") — capitalisation injectée" } patch_block_before_match() { local file="$1" local match="$2" local fragment_file="$3" if [ ! -f "$file" ]; then echo " [skip] $(basename "$file") — fichier absent" return 0 fi if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then echo " [skip] $(basename "$file") — capitalisation déjà présente" return 0 fi local rendered_fragment rendered_fragment="$(render_template_to_temp_file "$fragment_file")" awk -v match="$match" -v fragfile="$rendered_fragment" ' index($0, match) { while ((getline line < fragfile) > 0) print line close(fragfile) } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" rm -f "$rendered_fragment" echo " [ok] $(basename "$file") — capitalisation injectée" } patch_create_story_parallelization() { local file="$CREATE_STORY_XML" local fragment_file="$WORKFLOWS_DIR/create-story-parallelization.xmlfrag" if [ ! -f "$file" ]; then echo " [skip] $(basename "$file") — fichier absent" return 0 fi if grep -q "$CREATE_STORY_PARALLELIZATION_MARKER_XML" "$file"; then echo " [skip] $(basename "$file") — parallélisation create-story déjà présente" return 0 fi local rendered_fragment rendered_fragment="$(render_template_to_temp_file "$fragment_file")" awk -v fragfile="$rendered_fragment" ' /story_header<\/template-output>/ { print while ((getline line < fragfile) > 0) print line close(fragfile) next } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" rm -f "$rendered_fragment" echo " [ok] $(basename "$file") — règle create-story injectée" } patch_story_template() { local file="$STORY_TEMPLATE_MD" local fragment_file="$WORKFLOWS_DIR/story-template-frontmatter.mdfrag" if [ ! -f "$file" ]; then echo " [skip] $(basename "$file") — fichier absent" return 0 fi if grep -q "^Parallel-safe:" "$file"; then echo " [skip] $(basename "$file") — parallélisation déjà présente" return 0 fi local rendered_fragment rendered_fragment="$(render_template_to_temp_file "$fragment_file")" awk -v fragfile="$rendered_fragment" ' /^Status:/ { print while ((getline line < fragfile) > 0) print line close(fragfile) next } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" rm -f "$rendered_fragment" echo " [ok] $(basename "$file") — frontmatter de parallélisation injecté" } patch_dev_story_parallelization() { local file="$DEV_STORY_XML" local fragment_file="$WORKFLOWS_DIR/dev-story-parallelization-check.xmlfrag" if [ ! -f "$file" ]; then echo " [skip] $(basename "$file") — fichier absent" return 0 fi if grep -q "$PARALLELIZATION_MARKER_XML" "$file"; then echo " [skip] $(basename "$file") — parallélisation déjà présente" return 0 fi local rendered_fragment rendered_fragment="$(render_template_to_temp_file "$fragment_file")" awk -v fragfile="$rendered_fragment" ' // { while ((getline line < fragfile) > 0) print line close(fragfile) print next } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" rm -f "$rendered_fragment" echo " [ok] $(basename "$file") — règle de parallélisation injectée" } patch_agent() { local agent="$1" local template_name="$2" local file="$AGENTS_DIR/${agent}.customize.yaml" local template_file="$MEMORIES_DIR/${template_name}.txt" if [ ! -f "$file" ]; then return 0 fi require_file "$template_file" if grep -q "$CAPITALIZE_MARKER" "$file"; then echo " [skip] $agent — memory déjà présente" return 0 fi if ! grep -q "^memories: \[\]" "$file"; then echo " [warn] $agent — format memories: inattendu, patch manuel requis" return 0 fi local memory memory="$(render_template "$template_file")" awk -v mem="$memory" ' /^memories: \[\]/ { print "memories:"; print " - \"" mem "\""; next } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" echo " [ok] $agent — memory injectée" } patch_agents() { require_file "$PRODUCER_AGENTS_CONFIG" while IFS=$'\t' read -r agent template_name; do if [ -z "${agent:-}" ] || [ "${agent#\#}" != "$agent" ]; then continue fi patch_agent "$agent" "$template_name" done < "$PRODUCER_AGENTS_CONFIG" } patch_dev_story() { patch_block_before_match \ "$DEV_STORY_XML" \ "" \ "$WORKFLOWS_DIR/dev-story-capitalisation.xmlfrag" } patch_code_review() { local file="$CODE_REVIEW_XML" local fragment_file="$WORKFLOWS_DIR/code-review-capitalisation.xmlfrag" if [ ! -f "$file" ]; then echo " [skip] $(basename "$file") — fichier absent" return 0 fi if grep -q "$CAPITALIZE_MARKER_XML" "$file"; then echo " [skip] $(basename "$file") — capitalisation déjà présente" return 0 fi local rendered_fragment rendered_fragment="$(render_template_to_temp_file "$fragment_file")" awk -v fragfile="$rendered_fragment" ' /✅ Review Complete!/ { in_review_complete = 1 } in_review_complete && /<\/output>/ { print print "" while ((getline line < fragfile) > 0) print line close(fragfile) in_review_complete = 0 next } { print } ' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" rm -f "$rendered_fragment" echo " [ok] $(basename "$file") — capitalisation injectée" } patch_dev_story_checklist() { patch_line_after_match \ "$DEV_STORY_CHECKLIST" \ "**User Communication Ready**" \ "$WORKFLOWS_DIR/dev-story-checklist.mdfrag" } patch_code_review_checklist() { patch_line_after_match \ "$CODE_REVIEW_CHECKLIST" \ "Story saved successfully" \ "$WORKFLOWS_DIR/code-review-checklist.mdfrag" } patch_claude_md() { local fragment_file="$CLAUDE_FRAGMENTS_DIR/leadtech-capitalisation.mdfrag" if [ ! -f "$CLAUDE_MD" ]; then echo " [skip] CLAUDE.md — fichier absent" return 0 fi if grep -q "$CAPITALIZE_MARKER" "$CLAUDE_MD"; then echo " [skip] CLAUDE.md — section capitalisation déjà présente" return 0 fi render_template "$fragment_file" >> "$CLAUDE_MD" echo " [ok] CLAUDE.md — section capitalisation ajoutée" } # --- Main --- echo "" echo "post-bmad-install — injection Lead_tech capitalisation" echo "Projet : $PROJECT_NAME ($PROJECT_ROOT)" echo "Agents : $AGENTS_DIR" echo "Templates : $TEMPLATES_DIR" echo "" echo "Patch agents :" patch_agents echo "" echo "Patch workflows :" patch_story_template patch_create_story_parallelization patch_dev_story_parallelization patch_dev_story patch_code_review patch_dev_story_checklist patch_code_review_checklist echo "" echo "Patch CLAUDE.md :" patch_claude_md echo "" echo "Terminé. Lance 'git diff' pour vérifier les changements."