BMAD-METHOD/bmad-core/tasks/auto-language-init.md

279 lines
12 KiB
Markdown

# Auto Language Initialization
Automatic language detection and configuration that runs once per session to set up environment variables for all subsequent BMAD tasks.
[[LLM: This task runs automatically on first BMAD command to detect project language and configure all subsequent tasks]]
## Auto-Initialization System
### 1. **Session-Based Auto-Detection** (50-100 tokens)
```bash
# Auto-initialize language environment if not already done
auto_init_language_environment() {
local CACHE_FILE="tmp/bmad-session.json"
# Check if already initialized this session
if [ -f "$CACHE_FILE" ]; then
SESSION_AGE=$(jq -r '.initialized_at // "1970-01-01"' "$CACHE_FILE")
if [ "$(date -d "$SESSION_AGE" +%s)" -gt "$(date -d '2 hours ago' +%s)" ]; then
# Load cached environment variables
source <(jq -r '.environment | to_entries[] | "export " + .key + "=\"" + .value + "\""' "$CACHE_FILE")
echo "🔄 Using cached language environment: $BMAD_PRIMARY_LANGUAGE"
return 0
fi
fi
echo "🔍 Auto-detecting project language..."
# Rapid language detection
PROJECT_DIR="${1:-.}"
PRIMARY_LANGUAGE="unknown"
BUILD_COMMAND="echo 'No build system detected'"
TEST_COMMAND="echo 'No test system detected'"
SIMULATION_PATTERNS="TODO|FIXME|HACK"
ERROR_PATTERNS="error:|Error:"
COMPONENT_PATTERNS="[A-Z][a-zA-Z]*Service|[A-Z][a-zA-Z]*Controller|[A-Z][a-zA-Z]*Repository"
FILE_EXTENSIONS="*.*"
# Multi-tier detection strategy for new/existing projects
# Tier 1: Config files (most reliable)
if [ -f "$PROJECT_DIR/package.json" ]; then
if grep -q '"typescript":\|"@types/\|"ts-' "$PROJECT_DIR/package.json" || [ -f "$PROJECT_DIR/tsconfig.json" ]; then
PRIMARY_LANGUAGE="typescript"
BUILD_COMMAND="npm run build 2>/dev/null || tsc --noEmit"
TEST_COMMAND="npm test"
SIMULATION_PATTERNS="Math\.random|jest\.fn|sinon\.|TODO|FIXME"
ERROR_PATTERNS="TS[0-9]{4}|error TS"
FILE_EXTENSIONS="*.ts|*.tsx"
else
PRIMARY_LANGUAGE="javascript"
BUILD_COMMAND="npm run build 2>/dev/null || echo 'No build step'"
TEST_COMMAND="npm test"
SIMULATION_PATTERNS="Math\.random|jest\.fn|sinon\.|TODO|FIXME"
ERROR_PATTERNS="Error:|SyntaxError:"
FILE_EXTENSIONS="*.js|*.jsx"
fi
elif ls "$PROJECT_DIR"/*.csproj >/dev/null 2>&1 || [ -f "$PROJECT_DIR"/*.sln ]; then
PRIMARY_LANGUAGE="csharp"
BUILD_COMMAND="dotnet build --verbosity quiet"
TEST_COMMAND="dotnet test --verbosity quiet"
SIMULATION_PATTERNS="Random\.NextDouble|Task\.FromResult|NotImplementedException|Mock\.|Fake\.|Stub\."
ERROR_PATTERNS="CS[0-9]{4}"
FILE_EXTENSIONS="*.cs"
elif [ -f "$PROJECT_DIR/pom.xml" ] || [ -f "$PROJECT_DIR/build.gradle" ]; then
PRIMARY_LANGUAGE="java"
BUILD_COMMAND="mvn compile -q 2>/dev/null || gradle build -q"
TEST_COMMAND="mvn test -q 2>/dev/null || gradle test -q"
SIMULATION_PATTERNS="Math\.random|Mockito\.|@Mock|TODO|FIXME"
ERROR_PATTERNS="error:"
FILE_EXTENSIONS="*.java"
elif [ -f "$PROJECT_DIR/Cargo.toml" ]; then
PRIMARY_LANGUAGE="rust"
BUILD_COMMAND="cargo build --quiet"
TEST_COMMAND="cargo test --quiet"
SIMULATION_PATTERNS="todo!|unimplemented!|panic!|TODO|FIXME"
ERROR_PATTERNS="error\[E[0-9]{4}\]"
FILE_EXTENSIONS="*.rs"
elif [ -f "$PROJECT_DIR/go.mod" ]; then
PRIMARY_LANGUAGE="go"
BUILD_COMMAND="go build ./..."
TEST_COMMAND="go test ./..."
SIMULATION_PATTERNS="rand\.|mock\.|TODO|FIXME"
ERROR_PATTERNS="cannot find package|undefined:"
FILE_EXTENSIONS="*.go"
elif [ -f "$PROJECT_DIR/requirements.txt" ] || [ -f "$PROJECT_DIR/pyproject.toml" ] || [ -f "$PROJECT_DIR/setup.py" ]; then
PRIMARY_LANGUAGE="python"
BUILD_COMMAND="python -m py_compile *.py 2>/dev/null || echo 'Syntax check complete'"
TEST_COMMAND="python -m pytest"
SIMULATION_PATTERNS="random\.|mock\.|Mock\.|TODO|FIXME"
ERROR_PATTERNS="SyntaxError:|IndentationError:|NameError:"
FILE_EXTENSIONS="*.py"
elif [ -f "$PROJECT_DIR/Gemfile" ]; then
PRIMARY_LANGUAGE="ruby"
BUILD_COMMAND="ruby -c *.rb 2>/dev/null || echo 'Ruby syntax check'"
TEST_COMMAND="bundle exec rspec"
SIMULATION_PATTERNS="rand|mock|double|TODO|FIXME"
ERROR_PATTERNS="SyntaxError:|NameError:"
FILE_EXTENSIONS="*.rb"
elif [ -f "$PROJECT_DIR/composer.json" ]; then
PRIMARY_LANGUAGE="php"
BUILD_COMMAND="php -l *.php 2>/dev/null || echo 'PHP syntax check'"
TEST_COMMAND="vendor/bin/phpunit"
SIMULATION_PATTERNS="rand|mock|TODO|FIXME"
ERROR_PATTERNS="Parse error:|Fatal error:"
FILE_EXTENSIONS="*.php"
# Tier 2: File extension analysis (for new projects)
elif find "$PROJECT_DIR" -maxdepth 3 -name "*.ts" -o -name "*.tsx" | head -1 | grep -q .; then
PRIMARY_LANGUAGE="typescript"
BUILD_COMMAND="tsc --noEmit 2>/dev/null || echo 'TypeScript check (install: npm i -g typescript)'"
TEST_COMMAND="npm test 2>/dev/null || echo 'Install test framework'"
SIMULATION_PATTERNS="Math\.random|jest\.fn|TODO|FIXME"
ERROR_PATTERNS="TS[0-9]{4}|error TS"
FILE_EXTENSIONS="*.ts|*.tsx"
echo "💡 New TypeScript project detected - consider: npm init && npm install typescript"
elif find "$PROJECT_DIR" -maxdepth 3 -name "*.cs" | head -1 | grep -q .; then
PRIMARY_LANGUAGE="csharp"
BUILD_COMMAND="dotnet build --verbosity quiet 2>/dev/null || echo 'C# files found (install: dotnet CLI)'"
TEST_COMMAND="dotnet test --verbosity quiet"
SIMULATION_PATTERNS="Random\.NextDouble|Task\.FromResult|NotImplementedException"
ERROR_PATTERNS="CS[0-9]{4}"
FILE_EXTENSIONS="*.cs"
echo "💡 New C# project detected - consider: dotnet new console/webapi/classlib"
elif find "$PROJECT_DIR" -maxdepth 3 -name "*.java" | head -1 | grep -q .; then
PRIMARY_LANGUAGE="java"
BUILD_COMMAND="javac *.java 2>/dev/null || echo 'Java files found (setup: mvn/gradle)'"
TEST_COMMAND="mvn test 2>/dev/null || echo 'Setup Maven/Gradle'"
SIMULATION_PATTERNS="Math\.random|TODO|FIXME"
ERROR_PATTERNS="error:"
FILE_EXTENSIONS="*.java"
echo "💡 New Java project detected - consider: mvn archetype:generate"
elif find "$PROJECT_DIR" -maxdepth 3 -name "*.rs" | head -1 | grep -q .; then
PRIMARY_LANGUAGE="rust"
BUILD_COMMAND="rustc --version >/dev/null 2>&1 && echo 'Rust files found' || echo 'Install Rust toolchain'"
TEST_COMMAND="cargo test 2>/dev/null || echo 'Run: cargo init'"
SIMULATION_PATTERNS="todo!|unimplemented!|TODO"
ERROR_PATTERNS="error\[E[0-9]{4}\]"
FILE_EXTENSIONS="*.rs"
echo "💡 New Rust project detected - consider: cargo init"
elif find "$PROJECT_DIR" -maxdepth 3 -name "*.go" | head -1 | grep -q .; then
PRIMARY_LANGUAGE="go"
BUILD_COMMAND="go version >/dev/null 2>&1 && echo 'Go files found' || echo 'Install Go'"
TEST_COMMAND="go test ./... 2>/dev/null || echo 'Run: go mod init'"
SIMULATION_PATTERNS="TODO|FIXME"
ERROR_PATTERNS="undefined:|cannot find"
FILE_EXTENSIONS="*.go"
echo "💡 New Go project detected - consider: go mod init"
elif find "$PROJECT_DIR" -maxdepth 3 -name "*.py" | head -1 | grep -q .; then
PRIMARY_LANGUAGE="python"
BUILD_COMMAND="python -m py_compile *.py 2>/dev/null || echo 'Python files found'"
TEST_COMMAND="python -m pytest 2>/dev/null || echo 'Install: pip install pytest'"
SIMULATION_PATTERNS="random\.|TODO|FIXME"
ERROR_PATTERNS="SyntaxError:|NameError:"
FILE_EXTENSIONS="*.py"
echo "💡 New Python project detected - consider: pip install -r requirements.txt"
elif find "$PROJECT_DIR" -maxdepth 3 -name "*.js" -o -name "*.jsx" | head -1 | grep -q .; then
PRIMARY_LANGUAGE="javascript"
BUILD_COMMAND="node --version >/dev/null 2>&1 && echo 'JavaScript files found' || echo 'Install Node.js'"
TEST_COMMAND="npm test 2>/dev/null || echo 'Run: npm init'"
SIMULATION_PATTERNS="Math\.random|TODO|FIXME"
ERROR_PATTERNS="Error:|SyntaxError:"
FILE_EXTENSIONS="*.js|*.jsx"
echo "💡 New JavaScript project detected - consider: npm init"
# Tier 3: Directory/filename hints (empty projects)
elif [ -d "$PROJECT_DIR/src/main/java" ] || [ -d "$PROJECT_DIR/app/src/main/java" ]; then
PRIMARY_LANGUAGE="java"
BUILD_COMMAND="echo 'Java project structure detected - setup Maven/Gradle'"
TEST_COMMAND="echo 'Setup Maven: mvn archetype:generate'"
SIMULATION_PATTERNS="TODO|FIXME"
ERROR_PATTERNS="error:"
FILE_EXTENSIONS="*.java"
echo "💡 Java project structure detected - run: mvn archetype:generate"
elif [ -d "$PROJECT_DIR/src" ] && [ ! -f "$PROJECT_DIR/package.json" ] && [ ! -f "$PROJECT_DIR/*.csproj" ]; then
PRIMARY_LANGUAGE="generic"
BUILD_COMMAND="echo 'Generic project with src/ folder detected'"
TEST_COMMAND="echo 'Setup appropriate build system'"
SIMULATION_PATTERNS="TODO|FIXME|HACK"
ERROR_PATTERNS="error:|Error:"
FILE_EXTENSIONS="*.*"
echo "💡 Generic project structure - specify language manually if needed"
fi
# Cache environment for session
mkdir -p tmp
cat > "$CACHE_FILE" << EOF
{
"initialized_at": "$(date -Iseconds)",
"environment": {
"BMAD_PRIMARY_LANGUAGE": "$PRIMARY_LANGUAGE",
"BMAD_BUILD_COMMAND": "$BUILD_COMMAND",
"BMAD_TEST_COMMAND": "$TEST_COMMAND",
"BMAD_SIMULATION_PATTERNS": "$SIMULATION_PATTERNS",
"BMAD_ERROR_PATTERNS": "$ERROR_PATTERNS",
"BMAD_COMPONENT_PATTERNS": "$COMPONENT_PATTERNS",
"BMAD_FILE_EXTENSIONS": "$FILE_EXTENSIONS"
}
}
EOF
# Export environment variables for current session
export BMAD_PRIMARY_LANGUAGE="$PRIMARY_LANGUAGE"
export BMAD_BUILD_COMMAND="$BUILD_COMMAND"
export BMAD_TEST_COMMAND="$TEST_COMMAND"
export BMAD_SIMULATION_PATTERNS="$SIMULATION_PATTERNS"
export BMAD_ERROR_PATTERNS="$ERROR_PATTERNS"
export BMAD_COMPONENT_PATTERNS="$COMPONENT_PATTERNS"
export BMAD_FILE_EXTENSIONS="$FILE_EXTENSIONS"
echo "✅ Language environment initialized: $PRIMARY_LANGUAGE"
}
# Call auto-initialization (runs automatically when this task is loaded)
auto_init_language_environment
```
## Integration Method
### 2. **Automatic Task Wrapper**
Instead of individual tasks calling language detection, each optimized task starts with:
```bash
#!/bin/bash
# Auto-initialize language environment if needed
if [ -z "$BMAD_PRIMARY_LANGUAGE" ]; then
Read tool: bmad-core/tasks/auto-language-init.md
fi
# Now use language-specific variables directly
echo "🔍 Smart Build Context Analysis ($BMAD_PRIMARY_LANGUAGE)"
BUILD_OUTPUT=$($BMAD_BUILD_COMMAND 2>&1)
# ... rest of task logic
```
### 3. **Agent-Level Auto-Initialization**
Add to both dev and qa agent startup:
```yaml
session_initialization:
- auto_init_language_environment # Runs once per agent session
enhanced_commands:
- "*smart-build-context" # Uses pre-initialized environment
- "*smart-reality-audit" # Uses pre-initialized environment
- "*smart-story-mapping" # Uses pre-initialized environment
```
## Execution Flow
### **How It Works in Practice:**
```bash
# User runs: *smart-reality-audit story.md
1. Agent starts executing smart-reality-audit task
2. Task checks: "Is BMAD_PRIMARY_LANGUAGE set?"
3. If not: Runs auto-language-init.md (50-100 tokens, once per session)
4. If yes: Skips initialization (0 tokens)
5. Task uses $BMAD_BUILD_COMMAND, $BMAD_SIMULATION_PATTERNS directly
6. All subsequent tasks in session use cached environment (0 additional tokens)
```
### **Token Usage:**
- **First task in session**: 50-100 tokens for initialization
- **All subsequent tasks**: 0 additional tokens (uses cached environment)
- **Session reuse**: Environment cached for 2 hours
## Benefits of This Approach
**Fully Automatic** - No manual commands needed
**Session Efficient** - Initialize once, use everywhere
**Zero Integration Overhead** - Tasks just check environment variables
**Language Agnostic** - Works with any supported language
**Minimal Token Cost** - 50-100 tokens per session vs per task
This makes language adaptation **completely transparent** to the user while maintaining all optimization benefits!