-
Notifications
You must be signed in to change notification settings - Fork 4.6k
feat: Add /cross-feature command for analysis across features with Systems Thinking #723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
152d701
0939b57
23149f7
756e1b7
05db10d
5b03f3c
a9bad54
7e2363b
3a68b81
7ad4722
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,140 @@ | ||||||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||||||
| # Analyze current feature alignment with all existing features using systems thinking | ||||||||||||||||||||||||||||
| set -e | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Platform detection is done inline where sed is used for better portability | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| JSON_MODE=false | ||||||||||||||||||||||||||||
| ARGS=() | ||||||||||||||||||||||||||||
| for arg in "$@"; do | ||||||||||||||||||||||||||||
| case "$arg" in | ||||||||||||||||||||||||||||
| --json) JSON_MODE=true ;; | ||||||||||||||||||||||||||||
| --help|-h) echo "Usage: $0 [--json] [analysis_focus]"; exit 0 ;; | ||||||||||||||||||||||||||||
| *) ARGS+=("$arg") ;; | ||||||||||||||||||||||||||||
| esac | ||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| ANALYSIS_FOCUS="${ARGS[*]}" | ||||||||||||||||||||||||||||
| if [ -z "$ANALYSIS_FOCUS" ]; then | ||||||||||||||||||||||||||||
| ANALYSIS_FOCUS="Comprehensive Analysis" | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Resolve repository root. Prefer git information when available, but fall back | ||||||||||||||||||||||||||||
| # to the script location so the workflow still functions in repositories that | ||||||||||||||||||||||||||||
| # were initialised with --no-git. | ||||||||||||||||||||||||||||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||||||||||||||||||||||||||||
| FALLBACK_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" | ||||||||||||||||||||||||||||
| if git rev-parse --show-toplevel >/dev/null 2>&1; then | ||||||||||||||||||||||||||||
| REPO_ROOT=$(git rev-parse --show-toplevel) | ||||||||||||||||||||||||||||
| HAS_GIT=true | ||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||
| REPO_ROOT="$FALLBACK_ROOT" | ||||||||||||||||||||||||||||
| HAS_GIT=false | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| cd "$REPO_ROOT" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Get current branch name and find current spec | ||||||||||||||||||||||||||||
| if [ "$HAS_GIT" = true ]; then | ||||||||||||||||||||||||||||
| CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) | ||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||
| # If no git, try to determine current feature from specs directory | ||||||||||||||||||||||||||||
| # This is a fallback - in practice, alignment analysis should run on active feature branch | ||||||||||||||||||||||||||||
| CURRENT_BRANCH=$(ls -t specs/ | head -n 1 2>/dev/null || echo "") | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if [ -z "$CURRENT_BRANCH" ] || [ "$CURRENT_BRANCH" = "main" ] || [ "$CURRENT_BRANCH" = "master" ]; then | ||||||||||||||||||||||||||||
| echo "Error: Alignment analysis must be run from a feature branch (created by /speckit.specify)" >&2 | ||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| CURRENT_SPEC="$REPO_ROOT/specs/$CURRENT_BRANCH/spec.md" | ||||||||||||||||||||||||||||
| if [ ! -f "$CURRENT_SPEC" ]; then | ||||||||||||||||||||||||||||
| echo "Error: Current specification not found at $CURRENT_SPEC" >&2 | ||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Find all existing specifications | ||||||||||||||||||||||||||||
| ALL_SPECS=() | ||||||||||||||||||||||||||||
| SPECS_DIR="$REPO_ROOT/specs" | ||||||||||||||||||||||||||||
| if [ -d "$SPECS_DIR" ]; then | ||||||||||||||||||||||||||||
| for dir in "$SPECS_DIR"/*; do | ||||||||||||||||||||||||||||
| [ -d "$dir" ] || continue | ||||||||||||||||||||||||||||
| spec_file="$dir/spec.md" | ||||||||||||||||||||||||||||
| if [ -f "$spec_file" ] && [ "$spec_file" != "$CURRENT_SPEC" ]; then | ||||||||||||||||||||||||||||
| ALL_SPECS+=("$spec_file") | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Create analysis file in current feature directory | ||||||||||||||||||||||||||||
| FEATURE_DIR="$(dirname "$CURRENT_SPEC")" | ||||||||||||||||||||||||||||
| ANALYSIS_FILE="$FEATURE_DIR/cross-feature-analysis.md" | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Create analysis file from template | ||||||||||||||||||||||||||||
| TEMPLATE="$REPO_ROOT/templates/cross-feature-analysis-template.md" | ||||||||||||||||||||||||||||
| if [ -f "$TEMPLATE" ]; then | ||||||||||||||||||||||||||||
| cp "$TEMPLATE" "$ANALYSIS_FILE" | ||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||
| touch "$ANALYSIS_FILE" | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Extract clarification line from template to avoid duplication | ||||||||||||||||||||||||||||
| COMMAND_TEMPLATE="$REPO_ROOT/templates/commands/cross-feature.md" | ||||||||||||||||||||||||||||
| if [ -f "$COMMAND_TEMPLATE" ]; then | ||||||||||||||||||||||||||||
| # Extract the clarification message from the template (handles both quotes and backticks) | ||||||||||||||||||||||||||||
| CLARIFICATION_LINE=$(grep -A 1 "Add:" "$COMMAND_TEMPLATE" | grep "NEEDS CLARIFICATION" | sed 's/.*["'\''`]\(.*NEEDS CLARIFICATION.*\)["'\''`].*/\1/') | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Fallback if extraction fails | ||||||||||||||||||||||||||||
| # NOTE: This fallback must match the clarification line in templates/commands/cross-feature.md | ||||||||||||||||||||||||||||
| # The template is the source of truth - update there first if changing this message | ||||||||||||||||||||||||||||
| if [ -z "$CLARIFICATION_LINE" ]; then | ||||||||||||||||||||||||||||
| CLARIFICATION_LINE="- [NEEDS CLARIFICATION: Review cross-feature alignment analysis in cross-feature-analysis.md - potential conflicts identified that may require spec adjustments]" | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # Find the Requirements section and add the clarification line | ||||||||||||||||||||||||||||
| if [ -f "$CURRENT_SPEC" ]; then | ||||||||||||||||||||||||||||
| # Check if the clarification line already exists to avoid duplicates | ||||||||||||||||||||||||||||
| if ! grep -q "cross-feature-analysis.md" "$CURRENT_SPEC"; then | ||||||||||||||||||||||||||||
| # Find the line with "### Functional Requirements" and add our clarification after it | ||||||||||||||||||||||||||||
| if grep -q "### Functional Requirements" "$CURRENT_SPEC"; then | ||||||||||||||||||||||||||||
| # Use portable sed in-place editing for macOS and GNU/Linux | ||||||||||||||||||||||||||||
| if sed --version >/dev/null 2>&1; then | ||||||||||||||||||||||||||||
| # GNU sed | ||||||||||||||||||||||||||||
| sed -i "/### Functional Requirements/a\\$CLARIFICATION_LINE" "$CURRENT_SPEC" | ||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||
| # BSD/macOS sed | ||||||||||||||||||||||||||||
| sed -i.bak "/### Functional Requirements/a\\ | ||||||||||||||||||||||||||||
| $CLARIFICATION_LINE" "$CURRENT_SPEC" && rm -f "$CURRENT_SPEC.bak" | ||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||
|
Comment on lines
+103
to
+110
|
||||||||||||||||||||||||||||
| if sed --version >/dev/null 2>&1; then | |
| # GNU sed | |
| sed -i "/### Functional Requirements/a\\$CLARIFICATION_LINE" "$CURRENT_SPEC" | |
| else | |
| # BSD/macOS sed | |
| sed -i.bak "/### Functional Requirements/a\\ | |
| $CLARIFICATION_LINE" "$CURRENT_SPEC" && rm -f "$CURRENT_SPEC.bak" | |
| fi | |
| # Use awk to insert the clarification line after "### Functional Requirements" in a portable way | |
| awk -v line="$CLARIFICATION_LINE" ' | |
| $0 ~ /### Functional Requirements/ { print; print line; next } | |
| { print } | |
| ' "$CURRENT_SPEC" > "$CURRENT_SPEC.tmp" && mv "$CURRENT_SPEC.tmp" "$CURRENT_SPEC" |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,140 @@ | ||||
| # Analyze current feature alignment with all existing features using systems thinking | ||||
| param( | ||||
| [string]$Json = "", | ||||
| [string[]]$Args = @() | ||||
| ) | ||||
|
|
||||
| $JsonMode = $Json -eq "{ARGS}" -or $Args -contains "--json" | ||||
| $AnalysisFocus = ($Args | Where-Object { $_ -ne "--json" }) -join " " | ||||
| if ([string]::IsNullOrWhiteSpace($AnalysisFocus)) { | ||||
| $AnalysisFocus = "Comprehensive Analysis" | ||||
| } | ||||
|
|
||||
| # Get repository root | ||||
| $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition | ||||
| $FallbackRoot = Resolve-Path (Join-Path $ScriptDir "../..") | ||||
|
|
||||
| try { | ||||
| $RepoRoot = git rev-parse --show-toplevel 2>$null | ||||
| $HasGit = $true | ||||
| } catch { | ||||
| $RepoRoot = $FallbackRoot | ||||
| $HasGit = $false | ||||
| } | ||||
|
|
||||
| Set-Location $RepoRoot | ||||
|
|
||||
| # Get current branch name and find current spec | ||||
| if ($HasGit) { | ||||
| try { | ||||
| $CurrentBranch = git rev-parse --abbrev-ref HEAD 2>$null | ||||
| } catch { | ||||
| $CurrentBranch = "" | ||||
| } | ||||
| } else { | ||||
| # If no git, try to determine current feature from specs directory | ||||
| $SpecsDirs = Get-ChildItem -Path "specs" -Directory -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | ||||
| $CurrentBranch = if ($SpecsDirs) { $SpecsDirs[0].Name } else { "" } | ||||
| } | ||||
|
|
||||
| if ([string]::IsNullOrWhiteSpace($CurrentBranch) -or $CurrentBranch -eq "main" -or $CurrentBranch -eq "master") { | ||||
| Write-Error "Error: Alignment analysis must be run from a feature branch (created by /speckit.specify)" | ||||
| exit 1 | ||||
| } | ||||
|
|
||||
| $CurrentSpec = Join-Path $RepoRoot "specs" $CurrentBranch "spec.md" | ||||
| if (-not (Test-Path $CurrentSpec)) { | ||||
| Write-Error "Error: Current specification not found at $CurrentSpec" | ||||
| exit 1 | ||||
| } | ||||
|
|
||||
| # Find all existing specifications | ||||
| $AllSpecs = @() | ||||
| $SpecsDir = Join-Path $RepoRoot "specs" | ||||
| if (Test-Path $SpecsDir) { | ||||
| $SpecDirs = Get-ChildItem -Path $SpecsDir -Directory | ||||
| foreach ($dir in $SpecDirs) { | ||||
| $SpecFile = Join-Path $dir.FullName "spec.md" | ||||
| if ((Test-Path $SpecFile) -and ($SpecFile -ne $CurrentSpec)) { | ||||
| $AllSpecs += $SpecFile | ||||
| } | ||||
| } | ||||
| } | ||||
|
|
||||
| # Create analysis file in current feature directory | ||||
| $FeatureDir = Split-Path -Parent $CurrentSpec | ||||
| $AnalysisFile = Join-Path $FeatureDir "cross-feature-analysis.md" | ||||
|
|
||||
| # Create analysis file from template | ||||
| $Template = Join-Path $RepoRoot "templates" "cross-feature-analysis-template.md" | ||||
| if (Test-Path $Template) { | ||||
| Copy-Item $Template $AnalysisFile | ||||
| } else { | ||||
| New-Item -ItemType File -Path $AnalysisFile -Force | Out-Null | ||||
| } | ||||
|
|
||||
| # Extract clarification line from template to avoid duplication | ||||
| $CommandTemplate = Join-Path $RepoRoot "templates" "commands" "cross-feature.md" | ||||
| $ClarificationLine = "" | ||||
|
|
||||
| if (Test-Path $CommandTemplate) { | ||||
| # Extract the clarification message from the template (handles both quotes and backticks) | ||||
| $TemplateContent = Get-Content $CommandTemplate -Raw | ||||
| if ($TemplateContent -match 'Add: ["''`]([^"''`]+)["''`]') { | ||||
| $ClarificationLine = $matches[1] | ||||
| } | ||||
| } | ||||
|
|
||||
| # Fallback if extraction fails | ||||
| # NOTE: This fallback must match the clarification line in templates/commands/cross-feature.md | ||||
| # The template is the source of truth - update there first if changing this message | ||||
| if ([string]::IsNullOrWhiteSpace($ClarificationLine)) { | ||||
| $ClarificationLine = "- [NEEDS CLARIFICATION: Review cross-feature alignment analysis in cross-feature-analysis.md - potential conflicts identified that may require spec adjustments]" | ||||
| } | ||||
|
|
||||
| # Find the Requirements section and add the clarification line | ||||
| if (Test-Path $CurrentSpec) { | ||||
| $SpecContent = Get-Content $CurrentSpec -Raw | ||||
|
|
||||
| # Check if the clarification line already exists to avoid duplicates | ||||
| if (-not $SpecContent.Contains("cross-feature-analysis.md")) { | ||||
| $Lines = Get-Content $CurrentSpec | ||||
| $NewLines = @() | ||||
| $Added = $false | ||||
|
|
||||
| foreach ($Line in $Lines) { | ||||
| $NewLines += $Line | ||||
| # Add clarification line after "### Functional Requirements" | ||||
| if ($Line -match "^### Functional Requirements" -and -not $Added) { | ||||
| $NewLines += $ClarificationLine | ||||
| $Added = $true | ||||
| } | ||||
| } | ||||
|
|
||||
| # If no Functional Requirements section found, add to end | ||||
| if (-not $Added) { | ||||
| $NewLines += "" | ||||
| $NewLines += $ClarificationLine | ||||
| } | ||||
|
|
||||
| # Write back to file | ||||
| $NewLines | Set-Content $CurrentSpec | ||||
| } | ||||
| } | ||||
|
|
||||
| # Build output | ||||
| if ($JsonMode) { | ||||
| $AllSpecsJson = $AllSpecs | ForEach-Object { "`"$_`"" } | Join-String -Separator "," | ||||
|
||||
| $AllSpecsJson = $AllSpecs | ForEach-Object { "`"$_`"" } | Join-String -Separator "," |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,49 @@ | ||||||
| --- | ||||||
| description: Analyze how the current feature aligns with existing features using systems thinking to identify conflicts, dependencies, and emergent behaviors. | ||||||
| scripts: | ||||||
| sh: scripts/bash/cross-feature-check-all-features.sh --json "{ARGS}" | ||||||
| ps: scripts/powershell/cross-feature-check-all-features.ps1 -Json "{ARGS}" | ||||||
| --- | ||||||
|
|
||||||
| The text the user typed after `/speckit.cross-feature` in the triggering message **is** optional analysis focus. If empty, perform comprehensive alignment analysis. Assume you always have it available in this conversation even if `{ARGS}` appears literally below. | ||||||
|
|
||||||
| Given the current feature specification and optional analysis focus, do this: | ||||||
|
|
||||||
| 1. Run the script `{SCRIPT}` from repo root and parse its JSON output for CURRENT_SPEC, ALL_SPECS, and ANALYSIS_FILE. All file paths must be absolute. | ||||||
| **IMPORTANT** You must only ever run this script once. The JSON is provided in the terminal as output - always refer to it to get the actual content you're looking for. | ||||||
|
|
||||||
| 2. Load `templates/cross-feature-analysis-template.md` to understand the alignment analysis framework structure. | ||||||
|
|
||||||
| 3. Read the current feature specification from CURRENT_SPEC to understand: | ||||||
| - Feature purpose and user scenarios | ||||||
| - Functional requirements | ||||||
| - Key entities and relationships | ||||||
|
|
||||||
| 4. Analyze ALL_SPECS (array of paths to existing specifications) to identify ONLY actual issues: | ||||||
| - **Real conflicts**: Does this feature conflict with existing features? (shared resources, timing issues, contradictory behavior) | ||||||
| - **Dependencies**: Does this feature depend on or modify behavior from existing features? | ||||||
| - **Side effects**: Will this feature cause unexpected problems in other features? | ||||||
| - **Questions**: What needs clarification about cross-feature interactions? | ||||||
|
|
||||||
| 5. Be concise and action-oriented: | ||||||
| - **Skip empty sections**: If there are no issues in a category, remove that section entirely | ||||||
| - **One-line summaries**: Issues, impacts, and fixes should each be one line | ||||||
| - **Questions not essays**: Raise specific questions, don't explain systems theory | ||||||
| - **Actionable only**: Only include information that requires a decision or action | ||||||
| - **Target length**: 50-100 lines total, not 500+ lines | ||||||
|
|
||||||
| 6. Write the alignment analysis to ANALYSIS_FILE using the template structure, including ONLY: | ||||||
| - Impact summary (interactions, risk level, action needed) | ||||||
| - Specific questions that need answers (if any) | ||||||
| - Actual issues found with other features (if any) | ||||||
| - Concrete recommendations (if any) | ||||||
| - Remove any sections that don't apply | ||||||
|
|
||||||
| 7. Add a single clarification line to the current spec.md file in the Requirements section: | ||||||
| - Add: `- [NEEDS CLARIFICATION: Review cross-feature alignment analysis in cross-feature-analysis.md - potential conflicts identified that may require spec adjustments]` | ||||||
harikrishnan83 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| - This ensures `/speckit.clarify` will pick up alignment issues naturally | ||||||
| - **Note:** Scripts should extract this clarification text programmatically from this template to avoid duplication | ||||||
|
||||||
| - **Note:** Scripts should extract this clarification text programmatically from this template to avoid duplication | |
| - **Note:** The clarification text is defined in a shared configuration file or constant for scripts to use, reducing maintenance overhead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The complex regex pattern with multiple quote types makes this line difficult to read and maintain. Consider breaking this into multiple steps or using a more straightforward extraction approach.