Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions scripts/bash/check-prerequisites.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
22 changes: 6 additions & 16 deletions scripts/bash/common.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
#!/usr/bin/env bash
# Common functions and variables for all scripts

# 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
}
# Set working directory
WORKING_DIR="$(pwd)"

# Get current branch, with fallback for non-git repositories
get_current_branch() {
Expand All @@ -27,8 +19,7 @@ get_current_branch() {
fi

# 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=""
Expand Down Expand Up @@ -81,21 +72,20 @@ check_feature_branch() {
return 0
}

get_feature_dir() { echo "$1/specs/$2"; }
get_feature_dir() { echo "$WORKING_DIR/specs/$1"; }
Copy link

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function signature changed from accepting two parameters (repo_root and branch) to one parameter (branch), but the function body references $1 which now represents the branch parameter. However, the function is called elsewhere in the codebase expecting the old two-parameter signature, which could cause incorrect behavior.

Copilot uses AI. Check for mistakes.

get_feature_paths() {
local repo_root=$(get_repo_root)
local current_branch=$(get_current_branch)
local has_git_repo="false"

if has_git; then
has_git_repo="true"
fi

local feature_dir=$(get_feature_dir "$repo_root" "$current_branch")
local feature_dir=$(get_feature_dir "$current_branch")

cat <<EOF
REPO_ROOT='$repo_root'
WORKING_DIR='$WORKING_DIR'
CURRENT_BRANCH='$current_branch'
HAS_GIT='$has_git_repo'
FEATURE_DIR='$feature_dir'
Expand Down
19 changes: 6 additions & 13 deletions scripts/bash/create-new-feature.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,18 @@ find_repo_root() {
return 1
}

# 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.
# Set working directory
Comment on lines 31 to +34
Copy link

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The find_repo_root function is now unused but still defined in the file. This dead code should be removed to improve maintainability.

Copilot uses AI. Check for mistakes.
WORKING_DIR="$(pwd)"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Check git availability
if git rev-parse --show-toplevel >/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
Expand Down Expand Up @@ -80,7 +72,8 @@ fi
FEATURE_DIR="$SPECS_DIR/$BRANCH_NAME"
mkdir -p "$FEATURE_DIR"

TEMPLATE="$REPO_ROOT/.specify/templates/spec-template.md"
TEMPLATE="$WORKING_DIR/.specify/templates/spec-template.md"

Copy link

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The empty line at line 76 appears to be unnecessary whitespace that doesn't add value to the code structure.

Suggested change

Copilot uses AI. Check for mistakes.
SPEC_FILE="$FEATURE_DIR/spec.md"
if [ -f "$TEMPLATE" ]; then cp "$TEMPLATE" "$SPEC_FILE"; else touch "$SPEC_FILE"; fi

Expand Down
2 changes: 1 addition & 1 deletion scripts/bash/setup-plan.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
26 changes: 13 additions & 13 deletions scripts/bash/update-agent-context.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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=""
Expand Down Expand Up @@ -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)

Expand Down
4 changes: 2 additions & 2 deletions scripts/powershell/check-prerequisites.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ 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
IMPL_PLAN = $paths.IMPL_PLAN
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)"
Expand Down
27 changes: 7 additions & 20 deletions scripts/powershell/common.ps1
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
#!/usr/bin/env pwsh
# Common PowerShell functions analogous to common.sh

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
}
# Set working directory
$script:WorkingDir = (Get-Location).Path

function Get-CurrentBranch {
# First check if SPECIFY_FEATURE environment variable is set
Expand All @@ -32,8 +21,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 = ""
Expand Down Expand Up @@ -88,18 +76,17 @@ function Test-FeatureBranch {
}

function Get-FeatureDir {
param([string]$RepoRoot, [string]$Branch)
Join-Path $RepoRoot "specs/$Branch"
param([string]$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 -Branch $currentBranch

[PSCustomObject]@{
REPO_ROOT = $repoRoot
WORKING_DIR = $script:WorkingDir
CURRENT_BRANCH = $currentBranch
HAS_GIT = $hasGit
FEATURE_DIR = $featureDir
Expand Down
43 changes: 8 additions & 35 deletions scripts/powershell/create-new-feature.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment on lines +17 to +18
Copy link

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable $workingDir should use consistent naming with other scripts. All other files use $WORKING_DIR (uppercase with underscore), but this uses camelCase. Consider changing to $WORKING_DIR = (Get-Location).Path for consistency.

Copilot uses AI. Check for mistakes.

# Check git availability
try {
$repoRoot = git rev-parse --show-toplevel 2>$null
git rev-parse --show-toplevel 2>$null | Out-Null
Copy link

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The git command output is being redirected to Out-Null but the error stream is still redirected to $null. For consistency, consider using git rev-parse --show-toplevel >$null 2>&1 or handle both streams uniformly.

Suggested change
git rev-parse --show-toplevel 2>$null | Out-Null
git rev-parse --show-toplevel >$null 2>&1

Copilot uses AI. Check for mistakes.
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
Expand Down Expand Up @@ -89,7 +61,8 @@ if ($hasGit) {
$featureDir = Join-Path $specsDir $branchName
New-Item -ItemType Directory -Path $featureDir -Force | Out-Null

$template = Join-Path $repoRoot '.specify/templates/spec-template.md'
$template = Join-Path $workingDir '.specify/templates/spec-template.md'

$specFile = Join-Path $featureDir 'spec.md'
if (Test-Path $template) {
Copy-Item $template $specFile -Force
Expand Down
3 changes: 2 additions & 1 deletion scripts/powershell/setup-plan.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
Expand Down
30 changes: 15 additions & 15 deletions scripts/powershell/update-agent-context.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ''
Expand Down Expand Up @@ -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 = @()
Expand Down Expand Up @@ -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
Expand Down