From c31f9ba97e438d63cd263ec6779ad61404f2ee66 Mon Sep 17 00:00:00 2001 From: Kiryl Chetyrbak Date: Tue, 23 Sep 2025 13:43:18 -0400 Subject: [PATCH 1/4] Use workdir as root for all folders instead of repo root --- scripts/bash/check-prerequisites.sh | 6 +-- scripts/bash/common.sh | 11 ++++-- scripts/bash/create-new-feature.sh | 18 +++------ scripts/bash/setup-plan.sh | 2 +- scripts/bash/update-agent-context.sh | 26 ++++++------- scripts/powershell/check-prerequisites.ps1 | 4 +- scripts/powershell/common.ps1 | 11 ++++-- scripts/powershell/create-new-feature.ps1 | 42 ++++----------------- scripts/powershell/setup-plan.ps1 | 3 +- scripts/powershell/update-agent-context.ps1 | 30 +++++++-------- 10 files changed, 62 insertions(+), 91 deletions(-) diff --git a/scripts/bash/check-prerequisites.sh b/scripts/bash/check-prerequisites.sh index f32b6245a..e3ba6bb7c 100644 --- a/scripts/bash/check-prerequisites.sh +++ b/scripts/bash/check-prerequisites.sh @@ -86,10 +86,10 @@ check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1 if $PATHS_ONLY; then if $JSON_MODE; then # Minimal JSON paths payload (no validation performed) - printf '{"REPO_ROOT":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s"}\n' \ - "$REPO_ROOT" "$CURRENT_BRANCH" "$FEATURE_DIR" "$FEATURE_SPEC" "$IMPL_PLAN" "$TASKS" + printf '{"WORKING_DIR":"%s","BRANCH":"%s","FEATURE_DIR":"%s","FEATURE_SPEC":"%s","IMPL_PLAN":"%s","TASKS":"%s"}\n' \ + "$WORKING_DIR" "$CURRENT_BRANCH" "$FEATURE_DIR" "$FEATURE_SPEC" "$IMPL_PLAN" "$TASKS" else - echo "REPO_ROOT: $REPO_ROOT" + echo "WORKING_DIR: $WORKING_DIR" echo "BRANCH: $CURRENT_BRANCH" echo "FEATURE_DIR: $FEATURE_DIR" echo "FEATURE_SPEC: $FEATURE_SPEC" diff --git a/scripts/bash/common.sh b/scripts/bash/common.sh index 34e5d4bb7..57f90c87b 100644 --- a/scripts/bash/common.sh +++ b/scripts/bash/common.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash # Common functions and variables for all scripts +# Set working directory +WORKING_DIR="$(pwd)" + # Get repository root, with fallback for non-git repositories get_repo_root() { if git rev-parse --show-toplevel >/dev/null 2>&1; then @@ -28,7 +31,7 @@ get_current_branch() { # For non-git repos, try to find the latest feature directory local repo_root=$(get_repo_root) - local specs_dir="$repo_root/specs" + local specs_dir="$WORKING_DIR/specs" if [[ -d "$specs_dir" ]]; then local latest_feature="" @@ -81,7 +84,7 @@ check_feature_branch() { return 0 } -get_feature_dir() { echo "$1/specs/$2"; } +get_feature_dir() { echo "$WORKING_DIR/specs/$2"; } get_feature_paths() { local repo_root=$(get_repo_root) @@ -92,10 +95,10 @@ get_feature_paths() { has_git_repo="true" fi - local feature_dir=$(get_feature_dir "$repo_root" "$current_branch") + local feature_dir=$(get_feature_dir "$WORKING_DIR" "$current_branch") cat </dev/null 2>&1; then - REPO_ROOT=$(git rev-parse --show-toplevel) HAS_GIT=true else - REPO_ROOT="$(find_repo_root "$SCRIPT_DIR")" - if [ -z "$REPO_ROOT" ]; then - echo "Error: Could not determine repository root. Please run this script from within the repository." >&2 - exit 1 - fi HAS_GIT=false fi -cd "$REPO_ROOT" - -SPECS_DIR="$REPO_ROOT/specs" +SPECS_DIR="$WORKING_DIR/specs" mkdir -p "$SPECS_DIR" HIGHEST=0 @@ -80,7 +72,7 @@ fi FEATURE_DIR="$SPECS_DIR/$BRANCH_NAME" mkdir -p "$FEATURE_DIR" -TEMPLATE="$REPO_ROOT/templates/spec-template.md" +TEMPLATE="$WORKING_DIR/templates/spec-template.md" SPEC_FILE="$FEATURE_DIR/spec.md" if [ -f "$TEMPLATE" ]; then cp "$TEMPLATE" "$SPEC_FILE"; else touch "$SPEC_FILE"; fi diff --git a/scripts/bash/setup-plan.sh b/scripts/bash/setup-plan.sh index 654ba50d7..5af053ba6 100644 --- a/scripts/bash/setup-plan.sh +++ b/scripts/bash/setup-plan.sh @@ -37,7 +37,7 @@ check_feature_branch "$CURRENT_BRANCH" "$HAS_GIT" || exit 1 mkdir -p "$FEATURE_DIR" # Copy plan template if it exists -TEMPLATE="$REPO_ROOT/.specify/templates/plan-template.md" +TEMPLATE="$WORKING_DIR/.specify/templates/plan-template.md" if [[ -f "$TEMPLATE" ]]; then cp "$TEMPLATE" "$IMPL_PLAN" echo "Copied plan template to $IMPL_PLAN" diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index d3cc422ed..c1209dedc 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -58,20 +58,20 @@ eval $(get_feature_paths) NEW_PLAN="$IMPL_PLAN" # Alias for compatibility with existing code AGENT_TYPE="${1:-}" -# Agent-specific file paths -CLAUDE_FILE="$REPO_ROOT/CLAUDE.md" -GEMINI_FILE="$REPO_ROOT/GEMINI.md" -COPILOT_FILE="$REPO_ROOT/.github/copilot-instructions.md" -CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc" -QWEN_FILE="$REPO_ROOT/QWEN.md" -AGENTS_FILE="$REPO_ROOT/AGENTS.md" -WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md" -KILOCODE_FILE="$REPO_ROOT/.kilocode/rules/specify-rules.md" -AUGGIE_FILE="$REPO_ROOT/.augment/rules/specify-rules.md" -ROO_FILE="$REPO_ROOT/.roo/rules/specify-rules.md" +# Agent-specific file paths +CLAUDE_FILE="$WORKING_DIR/CLAUDE.md" +GEMINI_FILE="$WORKING_DIR/GEMINI.md" +COPILOT_FILE="$WORKING_DIR/.github/copilot-instructions.md" +CURSOR_FILE="$WORKING_DIR/.cursor/rules/specify-rules.mdc" +QWEN_FILE="$WORKING_DIR/QWEN.md" +AGENTS_FILE="$WORKING_DIR/AGENTS.md" +WINDSURF_FILE="$WORKING_DIR/.windsurf/rules/specify-rules.md" +KILOCODE_FILE="$WORKING_DIR/.kilocode/rules/specify-rules.md" +AUGGIE_FILE="$WORKING_DIR/.augment/rules/specify-rules.md" +ROO_FILE="$WORKING_DIR/.roo/rules/specify-rules.md" # Template file -TEMPLATE_FILE="$REPO_ROOT/.specify/templates/agent-file-template.md" +TEMPLATE_FILE="$WORKING_DIR/.specify/templates/agent-file-template.md" # Global variables for parsed plan data NEW_LANG="" @@ -481,7 +481,7 @@ update_agent_file() { log_info "Updating $agent_name context file: $target_file" local project_name - project_name=$(basename "$REPO_ROOT") + project_name=$(basename "$WORKING_DIR") local current_date current_date=$(date +%Y-%m-%d) diff --git a/scripts/powershell/check-prerequisites.ps1 b/scripts/powershell/check-prerequisites.ps1 index d61c3b994..577675c99 100644 --- a/scripts/powershell/check-prerequisites.ps1 +++ b/scripts/powershell/check-prerequisites.ps1 @@ -67,7 +67,7 @@ if (-not (Test-FeatureBranch -Branch $paths.CURRENT_BRANCH -HasGit:$paths.HAS_GI if ($PathsOnly) { if ($Json) { [PSCustomObject]@{ - REPO_ROOT = $paths.REPO_ROOT + WORKING_DIR = $paths.WORKING_DIR BRANCH = $paths.CURRENT_BRANCH FEATURE_DIR = $paths.FEATURE_DIR FEATURE_SPEC = $paths.FEATURE_SPEC @@ -75,7 +75,7 @@ if ($PathsOnly) { TASKS = $paths.TASKS } | ConvertTo-Json -Compress } else { - Write-Output "REPO_ROOT: $($paths.REPO_ROOT)" + Write-Output "WORKING_DIR: $($paths.WORKING_DIR)" Write-Output "BRANCH: $($paths.CURRENT_BRANCH)" Write-Output "FEATURE_DIR: $($paths.FEATURE_DIR)" Write-Output "FEATURE_SPEC: $($paths.FEATURE_SPEC)" diff --git a/scripts/powershell/common.ps1 b/scripts/powershell/common.ps1 index c8e34b26b..b664dedb4 100644 --- a/scripts/powershell/common.ps1 +++ b/scripts/powershell/common.ps1 @@ -1,6 +1,9 @@ #!/usr/bin/env pwsh # Common PowerShell functions analogous to common.sh +# Set working directory +$script:WorkingDir = (Get-Location).Path + function Get-RepoRoot { try { $result = git rev-parse --show-toplevel 2>$null @@ -33,7 +36,7 @@ function Get-CurrentBranch { # For non-git repos, try to find the latest feature directory $repoRoot = Get-RepoRoot - $specsDir = Join-Path $repoRoot "specs" + $specsDir = Join-Path $script:WorkingDir "specs" if (Test-Path $specsDir) { $latestFeature = "" @@ -89,17 +92,17 @@ function Test-FeatureBranch { function Get-FeatureDir { param([string]$RepoRoot, [string]$Branch) - Join-Path $RepoRoot "specs/$Branch" + Join-Path $script:WorkingDir "specs/$Branch" } function Get-FeaturePathsEnv { $repoRoot = Get-RepoRoot $currentBranch = Get-CurrentBranch $hasGit = Test-HasGit - $featureDir = Get-FeatureDir -RepoRoot $repoRoot -Branch $currentBranch + $featureDir = Get-FeatureDir -RepoRoot $script:WorkingDir -Branch $currentBranch [PSCustomObject]@{ - REPO_ROOT = $repoRoot + WORKING_DIR = $script:WorkingDir CURRENT_BRANCH = $currentBranch HAS_GIT = $hasGit FEATURE_DIR = $featureDir diff --git a/scripts/powershell/create-new-feature.ps1 b/scripts/powershell/create-new-feature.ps1 index f1c8e04e3..601858ae8 100644 --- a/scripts/powershell/create-new-feature.ps1 +++ b/scripts/powershell/create-new-feature.ps1 @@ -14,50 +14,22 @@ if (-not $FeatureDescription -or $FeatureDescription.Count -eq 0) { } $featureDesc = ($FeatureDescription -join ' ').Trim() -# Resolve repository root. Prefer git information when available, but fall back -# to searching for repository markers so the workflow still functions in repositories that -# were initialised with --no-git. -function Find-RepositoryRoot { - param( - [string]$StartDir, - [string[]]$Markers = @('.git', '.specify') - ) - $current = Resolve-Path $StartDir - while ($true) { - foreach ($marker in $Markers) { - if (Test-Path (Join-Path $current $marker)) { - return $current - } - } - $parent = Split-Path $current -Parent - if ($parent -eq $current) { - # Reached filesystem root without finding markers - return $null - } - $current = $parent - } -} -$fallbackRoot = (Find-RepositoryRoot -StartDir $PSScriptRoot) -if (-not $fallbackRoot) { - Write-Error "Error: Could not determine repository root. Please run this script from within the repository." - exit 1 -} +# Set working directory +$workingDir = Get-Location +# Check git availability try { - $repoRoot = git rev-parse --show-toplevel 2>$null + git rev-parse --show-toplevel 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { $hasGit = $true } else { - throw "Git not available" + $hasGit = $false } } catch { - $repoRoot = $fallbackRoot $hasGit = $false } -Set-Location $repoRoot - -$specsDir = Join-Path $repoRoot 'specs' +$specsDir = Join-Path $workingDir 'specs' New-Item -ItemType Directory -Path $specsDir -Force | Out-Null $highest = 0 @@ -89,7 +61,7 @@ if ($hasGit) { $featureDir = Join-Path $specsDir $branchName New-Item -ItemType Directory -Path $featureDir -Force | Out-Null -$template = Join-Path $repoRoot 'templates/spec-template.md' +$template = Join-Path $workingDir 'templates/spec-template.md' $specFile = Join-Path $featureDir 'spec.md' if (Test-Path $template) { Copy-Item $template $specFile -Force diff --git a/scripts/powershell/setup-plan.ps1 b/scripts/powershell/setup-plan.ps1 index d0ed582fa..7c1cdadcb 100644 --- a/scripts/powershell/setup-plan.ps1 +++ b/scripts/powershell/setup-plan.ps1 @@ -32,7 +32,8 @@ if (-not (Test-FeatureBranch -Branch $paths.CURRENT_BRANCH -HasGit $paths.HAS_GI New-Item -ItemType Directory -Path $paths.FEATURE_DIR -Force | Out-Null # Copy plan template if it exists, otherwise note it or create empty file -$template = Join-Path $paths.REPO_ROOT '.specify/templates/plan-template.md' +$workingDir = $paths.WORKING_DIR +$template = Join-Path $workingDir '.specify/templates/plan-template.md' if (Test-Path $template) { Copy-Item $template $paths.IMPL_PLAN -Force Write-Output "Copied plan template to $($paths.IMPL_PLAN)" diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index 8f4830a95..8e50a0d9a 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -37,25 +37,25 @@ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path # Acquire environment paths $envData = Get-FeaturePathsEnv -$REPO_ROOT = $envData.REPO_ROOT +$WORKING_DIR = $envData.WORKING_DIR $CURRENT_BRANCH = $envData.CURRENT_BRANCH $HAS_GIT = $envData.HAS_GIT $IMPL_PLAN = $envData.IMPL_PLAN $NEW_PLAN = $IMPL_PLAN # Agent file paths -$CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md' -$GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md' -$COPILOT_FILE = Join-Path $REPO_ROOT '.github/copilot-instructions.md' -$CURSOR_FILE = Join-Path $REPO_ROOT '.cursor/rules/specify-rules.mdc' -$QWEN_FILE = Join-Path $REPO_ROOT 'QWEN.md' -$AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md' -$WINDSURF_FILE = Join-Path $REPO_ROOT '.windsurf/rules/specify-rules.md' -$KILOCODE_FILE = Join-Path $REPO_ROOT '.kilocode/rules/specify-rules.md' -$AUGGIE_FILE = Join-Path $REPO_ROOT '.augment/rules/specify-rules.md' -$ROO_FILE = Join-Path $REPO_ROOT '.roo/rules/specify-rules.md' - -$TEMPLATE_FILE = Join-Path $REPO_ROOT '.specify/templates/agent-file-template.md' +$CLAUDE_FILE = Join-Path $WORKING_DIR 'CLAUDE.md' +$GEMINI_FILE = Join-Path $WORKING_DIR 'GEMINI.md' +$COPILOT_FILE = Join-Path $WORKING_DIR '.github/copilot-instructions.md' +$CURSOR_FILE = Join-Path $WORKING_DIR '.cursor/rules/specify-rules.mdc' +$QWEN_FILE = Join-Path $WORKING_DIR 'QWEN.md' +$AGENTS_FILE = Join-Path $WORKING_DIR 'AGENTS.md' +$WINDSURF_FILE = Join-Path $WORKING_DIR '.windsurf/rules/specify-rules.md' +$KILOCODE_FILE = Join-Path $WORKING_DIR '.kilocode/rules/specify-rules.md' +$AUGGIE_FILE = Join-Path $WORKING_DIR '.augment/rules/specify-rules.md' +$ROO_FILE = Join-Path $WORKING_DIR '.roo/rules/specify-rules.md' + +$TEMPLATE_FILE = Join-Path $WORKING_DIR '.specify/templates/agent-file-template.md' # Parsed plan data placeholders $script:NEW_LANG = '' @@ -265,7 +265,7 @@ function Update-ExistingAgentFile { [Parameter(Mandatory=$true)] [datetime]$Date ) - if (-not (Test-Path $TargetFile)) { return (New-AgentFile -TargetFile $TargetFile -ProjectName (Split-Path $REPO_ROOT -Leaf) -Date $Date) } + if (-not (Test-Path $TargetFile)) { return (New-AgentFile -TargetFile $TargetFile -ProjectName (Split-Path $WORKING_DIR -Leaf) -Date $Date) } $techStack = Format-TechnologyStack -Lang $NEW_LANG -Framework $NEW_FRAMEWORK $newTechEntries = @() @@ -340,7 +340,7 @@ function Update-AgentFile { ) if (-not $TargetFile -or -not $AgentName) { Write-Err 'Update-AgentFile requires TargetFile and AgentName'; return $false } Write-Info "Updating $AgentName context file: $TargetFile" - $projectName = Split-Path $REPO_ROOT -Leaf + $projectName = Split-Path $WORKING_DIR -Leaf $date = Get-Date $dir = Split-Path -Parent $TargetFile From a9eec6a1c4c6dd17e8ba6770e7830c45cef551cd Mon Sep 17 00:00:00 2001 From: Kiryl Chetyrbak Date: Tue, 23 Sep 2025 13:52:55 -0400 Subject: [PATCH 2/4] address copilot comment --- scripts/bash/common.sh | 4 ++-- scripts/powershell/common.ps1 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/bash/common.sh b/scripts/bash/common.sh index 57f90c87b..9340dd388 100644 --- a/scripts/bash/common.sh +++ b/scripts/bash/common.sh @@ -84,7 +84,7 @@ check_feature_branch() { return 0 } -get_feature_dir() { echo "$WORKING_DIR/specs/$2"; } +get_feature_dir() { echo "$WORKING_DIR/specs/$1"; } get_feature_paths() { local repo_root=$(get_repo_root) @@ -95,7 +95,7 @@ get_feature_paths() { has_git_repo="true" fi - local feature_dir=$(get_feature_dir "$WORKING_DIR" "$current_branch") + local feature_dir=$(get_feature_dir "$current_branch") cat < Date: Tue, 23 Sep 2025 14:26:06 -0400 Subject: [PATCH 3/4] address comments --- scripts/bash/common.sh | 13 +------------ scripts/powershell/common.ps1 | 16 +--------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/scripts/bash/common.sh b/scripts/bash/common.sh index 9340dd388..f024dad72 100644 --- a/scripts/bash/common.sh +++ b/scripts/bash/common.sh @@ -4,16 +4,7 @@ # Set working directory WORKING_DIR="$(pwd)" -# Get repository root, with fallback for non-git repositories -get_repo_root() { - if git rev-parse --show-toplevel >/dev/null 2>&1; then - git rev-parse --show-toplevel - else - # Fall back to script location for non-git repos - local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - (cd "$script_dir/../../.." && pwd) - fi -} +# Function removed - no longer needed since we use WORKING_DIR # Get current branch, with fallback for non-git repositories get_current_branch() { @@ -30,7 +21,6 @@ get_current_branch() { fi # For non-git repos, try to find the latest feature directory - local repo_root=$(get_repo_root) local specs_dir="$WORKING_DIR/specs" if [[ -d "$specs_dir" ]]; then @@ -87,7 +77,6 @@ check_feature_branch() { get_feature_dir() { echo "$WORKING_DIR/specs/$1"; } get_feature_paths() { - local repo_root=$(get_repo_root) local current_branch=$(get_current_branch) local has_git_repo="false" diff --git a/scripts/powershell/common.ps1 b/scripts/powershell/common.ps1 index 337bb1a2b..ae2416d30 100644 --- a/scripts/powershell/common.ps1 +++ b/scripts/powershell/common.ps1 @@ -4,19 +4,7 @@ # Set working directory $script:WorkingDir = (Get-Location).Path -function Get-RepoRoot { - try { - $result = git rev-parse --show-toplevel 2>$null - if ($LASTEXITCODE -eq 0) { - return $result - } - } catch { - # Git command failed - } - - # Fall back to script location for non-git repos - return (Resolve-Path (Join-Path $PSScriptRoot "../../..")).Path -} +# Function removed - no longer needed since we use WorkingDir function Get-CurrentBranch { # First check if SPECIFY_FEATURE environment variable is set @@ -35,7 +23,6 @@ function Get-CurrentBranch { } # For non-git repos, try to find the latest feature directory - $repoRoot = Get-RepoRoot $specsDir = Join-Path $script:WorkingDir "specs" if (Test-Path $specsDir) { @@ -96,7 +83,6 @@ function Get-FeatureDir { } function Get-FeaturePathsEnv { - $repoRoot = Get-RepoRoot $currentBranch = Get-CurrentBranch $hasGit = Test-HasGit $featureDir = Get-FeatureDir -Branch $currentBranch From 2318a5cce87f35be99fc872c1c402cbf1f87da38 Mon Sep 17 00:00:00 2001 From: Kiryl Chetyrbak Date: Tue, 23 Sep 2025 16:45:58 -0400 Subject: [PATCH 4/4] cleanup --- scripts/bash/common.sh | 2 -- scripts/powershell/common.ps1 | 2 -- 2 files changed, 4 deletions(-) diff --git a/scripts/bash/common.sh b/scripts/bash/common.sh index f024dad72..87fedc239 100644 --- a/scripts/bash/common.sh +++ b/scripts/bash/common.sh @@ -4,8 +4,6 @@ # Set working directory WORKING_DIR="$(pwd)" -# Function removed - no longer needed since we use WORKING_DIR - # Get current branch, with fallback for non-git repositories get_current_branch() { # First check if SPECIFY_FEATURE environment variable is set diff --git a/scripts/powershell/common.ps1 b/scripts/powershell/common.ps1 index ae2416d30..7c88c59db 100644 --- a/scripts/powershell/common.ps1 +++ b/scripts/powershell/common.ps1 @@ -4,8 +4,6 @@ # Set working directory $script:WorkingDir = (Get-Location).Path -# Function removed - no longer needed since we use WorkingDir - function Get-CurrentBranch { # First check if SPECIFY_FEATURE environment variable is set if ($env:SPECIFY_FEATURE) {