CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl-labs/intent-integrity-kit

Closing the intent-to-code chasm - specification-driven development with BDD verification chain

Overall
score

96%

Does it follow best practices?

Validation for skill structure

Overview
Skills
Evals
Files

setup-bdd.shskills/iikit-core/scripts/bash/

#!/usr/bin/env bash
# BDD Framework Scaffolding
# Auto-detects BDD framework from plan.md and scaffolds directory structure + dependencies
# Usage: setup-bdd.sh [--json] <features-dir> <plan-file>

set -euo pipefail

SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/common.sh"

# detect_framework() is defined in common.sh (returns "framework|language")

# =============================================================================
# EXISTING SCAFFOLDING CHECK
# =============================================================================

# Check if BDD scaffolding already exists
# Returns: "true" if both directories exist, "false" otherwise
check_existing_scaffolding() {
    local features_dir="$1"
    local step_defs_dir
    step_defs_dir="$(dirname "$features_dir")/step_definitions"

    if [[ -d "$features_dir" ]] && [[ -d "$step_defs_dir" ]]; then
        echo "true"
    else
        echo "false"
    fi
}

# =============================================================================
# DIRECTORY CREATION
# =============================================================================

create_directories() {
    local features_dir="$1"
    local step_defs_dir
    step_defs_dir="$(dirname "$features_dir")/step_definitions"
    local created=()

    if [[ ! -d "$features_dir" ]]; then
        mkdir -p "$features_dir"
        created+=("$(basename "$(dirname "$features_dir")")/features")
    fi

    if [[ ! -d "$step_defs_dir" ]]; then
        mkdir -p "$step_defs_dir"
        created+=("$(basename "$(dirname "$features_dir")")/step_definitions")
    fi

    # Output as JSON array
    local first=true
    printf '['
    for dir in "${created[@]}"; do
        if $first; then
            first=false
        else
            printf ','
        fi
        printf '"%s"' "$dir"
    done
    printf ']'
}

# =============================================================================
# FRAMEWORK INSTALLATION
# =============================================================================

# Install the BDD framework
# Returns: JSON array of installed packages, or instruction message
install_framework() {
    local framework="$1"
    local installed=()
    local instructions=""

    case "$framework" in
        pytest-bdd)
            if command -v pip >/dev/null 2>&1 || command -v pip3 >/dev/null 2>&1; then
                local pip_cmd="pip"
                command -v pip3 >/dev/null 2>&1 && pip_cmd="pip3"
                $pip_cmd install pytest-bdd >/dev/null 2>&1 && installed+=("pytest-bdd")
            fi
            ;;
        behave)
            if command -v pip >/dev/null 2>&1 || command -v pip3 >/dev/null 2>&1; then
                local pip_cmd="pip"
                command -v pip3 >/dev/null 2>&1 && pip_cmd="pip3"
                $pip_cmd install behave >/dev/null 2>&1 && installed+=("behave")
            fi
            ;;
        @cucumber/cucumber)
            if command -v npm >/dev/null 2>&1; then
                npm install --save-dev @cucumber/cucumber >/dev/null 2>&1 && installed+=("@cucumber/cucumber")
            fi
            ;;
        godog)
            if command -v go >/dev/null 2>&1; then
                go get github.com/cucumber/godog >/dev/null 2>&1 && installed+=("godog")
            fi
            ;;
        cucumber-jvm-maven)
            instructions="Add Cucumber-JVM dependency to pom.xml: io.cucumber:cucumber-java, io.cucumber:cucumber-junit-platform-engine"
            ;;
        cucumber-jvm-gradle)
            instructions="Add Cucumber-JVM dependency to build.gradle: io.cucumber:cucumber-java, io.cucumber:cucumber-junit-platform-engine"
            ;;
        cucumber-rs)
            instructions="Add cucumber dependency to Cargo.toml: cucumber = { version = \"0.20\" }"
            ;;
        reqnroll)
            if command -v dotnet >/dev/null 2>&1; then
                dotnet add package Reqnroll.NUnit >/dev/null 2>&1 && installed+=("Reqnroll.NUnit")
            fi
            ;;
    esac

    # Output as JSON array of installed packages
    local first=true
    printf '['
    for pkg in "${installed[@]}"; do
        if $first; then
            first=false
        else
            printf ','
        fi
        printf '"%s"' "$pkg"
    done
    printf ']'

    # Return instructions via stderr if needed (caller can capture)
    if [[ -n "$instructions" ]]; then
        echo "$instructions" >&2
    fi
}

# =============================================================================
# JSON OUTPUT
# =============================================================================

output_json() {
    local status="$1"
    local framework="$2"
    local language="$3"
    local dirs_created="$4"
    local pkgs_installed="$5"
    local message="${6:-}"

    if [[ "$status" == "NO_FRAMEWORK" ]]; then
        cat <<EOF
{"status":"NO_FRAMEWORK","framework":null,"language":"unknown","message":"No BDD framework detected for tech stack. Feature files will be generated without framework scaffolding."}
EOF
    else
        cat <<EOF
{"status":"${status}","framework":"${framework}","language":"${language}","directories_created":${dirs_created},"packages_installed":${pkgs_installed},"config_files_created":[]}
EOF
    fi
}

output_human() {
    local status="$1"
    local framework="$2"
    local language="$3"
    local dirs_created="$4"
    local pkgs_installed="$5"
    local message="${6:-}"

    case "$status" in
        SCAFFOLDED)
            echo "[setup-bdd] Scaffolded BDD framework: $framework ($language)"
            echo "  Directories: $dirs_created"
            echo "  Packages: $pkgs_installed"
            ;;
        ALREADY_SCAFFOLDED)
            echo "[setup-bdd] BDD scaffolding already exists for $framework ($language)"
            ;;
        NO_FRAMEWORK)
            echo "[setup-bdd] WARNING: No BDD framework detected for tech stack."
            echo "  Feature files will be generated without framework scaffolding."
            echo "  Directories created: $dirs_created"
            ;;
    esac
}

# =============================================================================
# MAIN
# =============================================================================

JSON_MODE=false
[[ "${1:-}" == "--json" ]] && { JSON_MODE=true; shift; }

FEATURES_DIR="${1:?Usage: setup-bdd.sh [--json] <features-dir> <plan-file>}"
PLAN_FILE="${2:?Usage: setup-bdd.sh [--json] <features-dir> <plan-file>}"

# Detect framework
detection=$(detect_framework "$PLAN_FILE")

if [[ -z "$detection" ]]; then
    # NO_FRAMEWORK fallback: create directories but no framework install
    dirs_created=$(create_directories "$FEATURES_DIR")

    if $JSON_MODE; then
        output_json "NO_FRAMEWORK" "" "" "$dirs_created" "[]"
    else
        output_human "NO_FRAMEWORK" "" "" "$dirs_created" "[]"
    fi
    exit 0
fi

# Parse detection result
framework="${detection%%|*}"
language="${detection##*|}"

# Check for existing scaffolding (idempotency)
already_scaffolded=$(check_existing_scaffolding "$FEATURES_DIR")

if [[ "$already_scaffolded" == "true" ]]; then
    if $JSON_MODE; then
        output_json "ALREADY_SCAFFOLDED" "$framework" "$language" "[]" "[]"
    else
        output_human "ALREADY_SCAFFOLDED" "$framework" "$language" "[]" "[]"
    fi
    exit 0
fi

# Create directories
dirs_created=$(create_directories "$FEATURES_DIR")

# Install framework (capture instructions from stderr)
instructions=""
pkgs_installed=$(install_framework "$framework" 2>/dev/null) || pkgs_installed="[]"

# Output result
if $JSON_MODE; then
    output_json "SCAFFOLDED" "$framework" "$language" "$dirs_created" "$pkgs_installed"
else
    output_human "SCAFFOLDED" "$framework" "$language" "$dirs_created" "$pkgs_installed"
fi

exit 0

Install with Tessl CLI

npx tessl i tessl-labs/intent-integrity-kit@2.3.5

skills

README.md

tile.json