Skip to content

Commit 59c4212

Browse files
committed
refactor: remove unused rate-limit helpers and improve PowerShell scripts
- Remove unused _parse_rate_limit_headers() and _format_rate_limit_error() from src/specify_cli/__init__.py (56 lines of dead code) - Add GENRELEASES_DIR override support to PowerShell release script with comprehensive safety checks (parity with bash script) - Remove redundant shared-file update calls from PowerShell agent context script (AMP_FILE, KIRO_FILE, BOB_FILE, FORGE_FILE all resolve to AGENTS.md) - Update test docstring to accurately reflect Forge's {{parameters}} token Changes align PowerShell scripts with bash equivalents and reduce maintenance burden by removing dead code.
1 parent 053ee8a commit 59c4212

4 files changed

Lines changed: 58 additions & 65 deletions

File tree

.github/workflows/scripts/create-release-packages.ps1

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
Comma or space separated subset of script types to build (default: both)
2121
Valid scripts: sh, ps
2222
23+
.PARAMETER GenReleasesDir
24+
Output directory for build artifacts (default: .genreleases in current directory)
25+
Can also be set via GENRELEASES_DIR environment variable
26+
2327
.EXAMPLE
2428
.\create-release-packages.ps1 -Version v0.2.0
2529
@@ -28,6 +32,12 @@
2832
2933
.EXAMPLE
3034
.\create-release-packages.ps1 -Version v0.2.0 -Agents claude -Scripts ps
35+
36+
.EXAMPLE
37+
$env:GENRELEASES_DIR = "$env:TEMP/releases"; .\create-release-packages.ps1 -Version v0.2.0
38+
39+
.EXAMPLE
40+
.\create-release-packages.ps1 -Version v0.2.0 -GenReleasesDir "$env:TEMP/releases"
3141
#>
3242

3343
param(
@@ -38,7 +48,10 @@ param(
3848
[string]$Agents = "",
3949

4050
[Parameter(Mandatory=$false)]
41-
[string]$Scripts = ""
51+
[string]$Scripts = "",
52+
53+
[Parameter(Mandatory=$false)]
54+
[string]$GenReleasesDir = ""
4255
)
4356

4457
$ErrorActionPreference = "Stop"
@@ -51,8 +64,49 @@ if ($Version -notmatch '^v\d+\.\d+\.\d+$') {
5164

5265
Write-Host "Building release packages for $Version"
5366

54-
# Create and use .genreleases directory for all build artifacts
55-
$GenReleasesDir = ".genreleases"
67+
# Resolve output directory: parameter > env var > default
68+
if ([string]::IsNullOrEmpty($GenReleasesDir)) {
69+
$GenReleasesDir = if ($env:GENRELEASES_DIR) { $env:GENRELEASES_DIR } else { ".genreleases" }
70+
}
71+
72+
# Safety check: refuse empty output directory
73+
if ([string]::IsNullOrWhiteSpace($GenReleasesDir)) {
74+
Write-Error "Output directory must not be empty"
75+
exit 1
76+
}
77+
78+
# Safety check: refuse paths containing '..' segments (path traversal)
79+
if ($GenReleasesDir -match '\.\.') {
80+
Write-Error "Refusing to use output directory containing '..' path segments: $GenReleasesDir"
81+
exit 1
82+
}
83+
84+
# Convert to absolute path for safety checks
85+
$GenReleasesDir = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($GenReleasesDir)
86+
87+
# Safety check: refuse to delete critical paths
88+
$repoRoot = (Resolve-Path ".").Path
89+
$forbiddenPaths = @(
90+
$repoRoot,
91+
(Join-Path $repoRoot ".git"),
92+
(Join-Path $repoRoot "scripts"),
93+
(Join-Path $repoRoot "templates"),
94+
(Join-Path $repoRoot "src"),
95+
$HOME,
96+
[System.IO.Path]::GetTempPath().TrimEnd([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar),
97+
[System.IO.Path]::GetPathRoot($repoRoot) # Root directory (e.g., C:\ or /)
98+
)
99+
100+
foreach ($forbidden in $forbiddenPaths) {
101+
if ($GenReleasesDir -eq $forbidden) {
102+
Write-Error "Refusing to use '$GenReleasesDir' as output directory (safety check failed)"
103+
exit 1
104+
}
105+
}
106+
107+
Write-Host "Output directory: $GenReleasesDir"
108+
109+
# Create and clean output directory
56110
if (Test-Path $GenReleasesDir) {
57111
Remove-Item -Path $GenReleasesDir -Recurse -Force -ErrorAction SilentlyContinue
58112
}

scripts/powershell/update-agent-context.ps1

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -461,9 +461,6 @@ function Update-AllExistingAgents {
461461
if (-not (Update-IfNew -FilePath $CURSOR_FILE -AgentName 'Cursor IDE')) { $ok = $false }
462462
if (-not (Update-IfNew -FilePath $QWEN_FILE -AgentName 'Qwen Code')) { $ok = $false }
463463
if (-not (Update-IfNew -FilePath $AGENTS_FILE -AgentName 'Codex/opencode/Amp/Kiro/Bob/Pi/Forge')) { $ok = $false }
464-
if (-not (Update-IfNew -FilePath $AMP_FILE -AgentName 'Amp')) { $ok = $false }
465-
if (-not (Update-IfNew -FilePath $KIRO_FILE -AgentName 'Kiro CLI')) { $ok = $false }
466-
if (-not (Update-IfNew -FilePath $BOB_FILE -AgentName 'IBM Bob')) { $ok = $false }
467464
if (-not (Update-IfNew -FilePath $WINDSURF_FILE -AgentName 'Windsurf')) { $ok = $false }
468465
if (-not (Update-IfNew -FilePath $JUNIE_FILE -AgentName 'Junie')) { $ok = $false }
469466
if (-not (Update-IfNew -FilePath $KILOCODE_FILE -AgentName 'Kilo Code')) { $ok = $false }
@@ -478,7 +475,6 @@ function Update-AllExistingAgents {
478475
if (-not (Update-IfNew -FilePath $KIMI_FILE -AgentName 'Kimi Code')) { $ok = $false }
479476
if (-not (Update-IfNew -FilePath $TRAE_FILE -AgentName 'Trae')) { $ok = $false }
480477
if (-not (Update-IfNew -FilePath $IFLOW_FILE -AgentName 'iFlow CLI')) { $ok = $false }
481-
if (-not (Update-IfNew -FilePath $FORGE_FILE -AgentName 'Forge')) { $ok = $false }
482478

483479
if (-not $found) {
484480
Write-Info 'No existing agent files found, creating default Claude file...'

src/specify_cli/__init__.py

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -67,63 +67,6 @@ def _github_auth_headers(cli_token: str | None = None) -> dict:
6767
token = _github_token(cli_token)
6868
return {"Authorization": f"Bearer {token}"} if token else {}
6969

70-
def _parse_rate_limit_headers(headers: httpx.Headers) -> dict:
71-
"""Extract and parse GitHub rate-limit headers."""
72-
info = {}
73-
74-
# Standard GitHub rate-limit headers
75-
if "X-RateLimit-Limit" in headers:
76-
info["limit"] = headers.get("X-RateLimit-Limit")
77-
if "X-RateLimit-Remaining" in headers:
78-
info["remaining"] = headers.get("X-RateLimit-Remaining")
79-
if "X-RateLimit-Reset" in headers:
80-
reset_epoch = int(headers.get("X-RateLimit-Reset", "0"))
81-
if reset_epoch:
82-
reset_time = datetime.fromtimestamp(reset_epoch, tz=timezone.utc)
83-
info["reset_epoch"] = reset_epoch
84-
info["reset_time"] = reset_time
85-
info["reset_local"] = reset_time.astimezone()
86-
87-
# Retry-After header (seconds or HTTP-date)
88-
if "Retry-After" in headers:
89-
retry_after = headers.get("Retry-After")
90-
try:
91-
info["retry_after_seconds"] = int(retry_after)
92-
except ValueError:
93-
# HTTP-date format - not implemented, just store as string
94-
info["retry_after"] = retry_after
95-
96-
return info
97-
98-
def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str) -> str:
99-
"""Format a user-friendly error message with rate-limit information."""
100-
rate_info = _parse_rate_limit_headers(headers)
101-
102-
lines = [f"GitHub API returned status {status_code} for {url}"]
103-
lines.append("")
104-
105-
if rate_info:
106-
lines.append("[bold]Rate Limit Information:[/bold]")
107-
if "limit" in rate_info:
108-
lines.append(f" • Rate Limit: {rate_info['limit']} requests/hour")
109-
if "remaining" in rate_info:
110-
lines.append(f" • Remaining: {rate_info['remaining']}")
111-
if "reset_local" in rate_info:
112-
reset_str = rate_info["reset_local"].strftime("%Y-%m-%d %H:%M:%S %Z")
113-
lines.append(f" • Resets at: {reset_str}")
114-
if "retry_after_seconds" in rate_info:
115-
lines.append(f" • Retry after: {rate_info['retry_after_seconds']} seconds")
116-
lines.append("")
117-
118-
# Add troubleshooting guidance
119-
lines.append("[bold]Troubleshooting Tips:[/bold]")
120-
lines.append(" • If you're on a shared CI or corporate environment, you may be rate-limited.")
121-
lines.append(" • Consider using a GitHub token via --github-token or the GH_TOKEN/GITHUB_TOKEN")
122-
lines.append(" environment variable to increase rate limits.")
123-
lines.append(" • Authenticated requests have a limit of 5,000/hour vs 60/hour for unauthenticated.")
124-
125-
return "\n".join(lines)
126-
12770
def _build_agent_config() -> dict[str, dict[str, Any]]:
12871
"""Derive AGENT_CONFIG from INTEGRATION_REGISTRY."""
12972
from .integrations import INTEGRATION_REGISTRY

tests/test_core_pack_scaffold.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
• File count matches the number of source templates
1616
• Extension is correct: .toml (TOML agents), .agent.md (copilot), .md (rest)
1717
• No unresolved placeholders remain ({SCRIPT}, {ARGS}, __AGENT__)
18-
• Argument token is correct: {{args}} for TOML agents, $ARGUMENTS for others
18+
• Argument token is correct: {{args}} for TOML agents, {{parameters}} for Forge, $ARGUMENTS for other non-TOML agents
1919
• Path rewrites applied: scripts/ → .specify/scripts/ etc.
2020
• TOML files have "description" and "prompt" fields
2121
• Markdown files have parseable YAML frontmatter

0 commit comments

Comments
 (0)