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
4 changes: 2 additions & 2 deletions .github/workflows/scripts/create-release-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ if [[ $# -ne 1 ]]; then
exit 1
fi
NEW_VERSION="$1"
if [[ ! $NEW_VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Version must look like v0.0.0" >&2
if [[ ! $NEW_VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9]+)?$ ]]; then
echo "Version must look like v0.0.0 or v0.0.0-pre" >&2
exit 1
fi

Expand Down
70 changes: 35 additions & 35 deletions src/specify_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def _github_auth_headers(cli_token: str | None = None) -> dict:
def _parse_rate_limit_headers(headers: httpx.Headers) -> dict:
"""Extract and parse GitHub rate-limit headers."""
info = {}

# Standard GitHub rate-limit headers
if "X-RateLimit-Limit" in headers:
info["limit"] = headers.get("X-RateLimit-Limit")
Expand All @@ -81,7 +81,7 @@ def _parse_rate_limit_headers(headers: httpx.Headers) -> dict:
info["reset_epoch"] = reset_epoch
info["reset_time"] = reset_time
info["reset_local"] = reset_time.astimezone()

# Retry-After header (seconds or HTTP-date)
if "Retry-After" in headers:
retry_after = headers.get("Retry-After")
Expand All @@ -90,16 +90,16 @@ def _parse_rate_limit_headers(headers: httpx.Headers) -> dict:
except ValueError:
# HTTP-date format - not implemented, just store as string
info["retry_after"] = retry_after

return info

def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str) -> str:
"""Format a user-friendly error message with rate-limit information."""
rate_info = _parse_rate_limit_headers(headers)

lines = [f"GitHub API returned status {status_code} for {url}"]
lines.append("")

if rate_info:
lines.append("[bold]Rate Limit Information:[/bold]")
if "limit" in rate_info:
Expand All @@ -112,14 +112,14 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str)
if "retry_after_seconds" in rate_info:
lines.append(f" • Retry after: {rate_info['retry_after_seconds']} seconds")
lines.append("")

# Add troubleshooting guidance
lines.append("[bold]Troubleshooting Tips:[/bold]")
lines.append(" • If you're on a shared CI or corporate environment, you may be rate-limited.")
lines.append(" • Consider using a GitHub token via --github-token or the GH_TOKEN/GITHUB_TOKEN")
lines.append(" environment variable to increase rate limits.")
lines.append(" • Authenticated requests have a limit of 5,000/hour vs 60/hour for unauthenticated.")

return "\n".join(lines)

# Agent configuration with name, folder, install URL, and CLI tool requirement
Expand Down Expand Up @@ -235,10 +235,10 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str)
BANNER = """
███████╗██████╗ ███████╗ ██████╗██╗███████╗██╗ ██╗
██╔════╝██╔══██╗██╔════╝██╔════╝██║██╔════╝╚██╗ ██╔╝
███████╗██████╔╝█████╗ ██║ ██║█████╗ ╚████╔╝
╚════██║██╔═══╝ ██╔══╝ ██║ ██║██╔══╝ ╚██╔╝
███████║██║ ███████╗╚██████╗██║██║ ██║
╚══════╝╚═╝ ╚══════╝ ╚═════╝╚═╝╚═╝ ╚═╝
███████╗██████╔╝█████╗ ██║ ██║█████╗ ╚████╔╝
╚════██║██╔═══╝ ██╔══╝ ██║ ██║██╔══╝ ╚██╔╝
███████║██║ ███████╗╚██████╗██║██║ ██║
╚══════╝╚═╝ ╚══════╝ ╚═════╝╚═╝╚═╝ ╚═╝
"""

TAGLINE = "GitHub Spec Kit - Spec-Driven Development Toolkit"
Expand Down Expand Up @@ -350,12 +350,12 @@ def get_key():
def select_with_arrows(options: dict, prompt_text: str = "Select an option", default_key: str = None) -> str:
"""
Interactive selection using arrow keys with Rich Live display.

Args:
options: Dict with keys as option keys and values as descriptions
prompt_text: Text to show above the options
default_key: Default option key to start with

Returns:
Selected option key
"""
Expand Down Expand Up @@ -483,11 +483,11 @@ def run_command(cmd: list[str], check_return: bool = True, capture: bool = False

def check_tool(tool: str, tracker: StepTracker = None) -> bool:
"""Check if a tool is installed. Optionally update tracker.

Args:
tool: Name of the tool to check
tracker: Optional StepTracker to update with results

Returns:
True if tool is found, False otherwise
"""
Expand All @@ -501,22 +501,22 @@ def check_tool(tool: str, tracker: StepTracker = None) -> bool:
if tracker:
tracker.complete(tool, "available")
return True

found = shutil.which(tool) is not None

if tracker:
if found:
tracker.complete(tool, "available")
else:
tracker.error(tool, "not found")

return found

def is_git_repo(path: Path = None) -> bool:
"""Check if the specified path is inside a git repository."""
if path is None:
path = Path.cwd()

if not path.is_dir():
return False

Expand All @@ -534,11 +534,11 @@ def is_git_repo(path: Path = None) -> bool:

def init_git_repo(project_path: Path, quiet: bool = False) -> Tuple[bool, Optional[str]]:
"""Initialize a git repository in the specified path.

Args:
project_path: Path to initialize git repository in
quiet: if True suppress console output (tracker handles status)

Returns:
Tuple of (success: bool, error_message: Optional[str])
"""
Expand All @@ -560,7 +560,7 @@ def init_git_repo(project_path: Path, quiet: bool = False) -> Tuple[bool, Option
error_msg += f"\nError: {e.stderr.strip()}"
elif e.stdout:
error_msg += f"\nOutput: {e.stdout.strip()}"

if not quiet:
console.print(f"[red]Error initializing git repository:[/red] {e}")
return False, error_msg
Expand Down Expand Up @@ -635,7 +635,7 @@ def deep_merge(base: dict, update: dict) -> dict:
return merged

def download_template_from_github(ai_assistant: str, download_dir: Path, *, script_type: str = "sh", verbose: bool = True, show_progress: bool = True, client: httpx.Client = None, debug: bool = False, github_token: str = None) -> Tuple[Path, dict]:
repo_owner = "github"
repo_owner = "young-hwang"
repo_name = "spec-kit"
if client is None:
client = httpx.Client(verify=ssl_context)
Expand Down Expand Up @@ -957,15 +957,15 @@ def init(
):
"""
Initialize a new Specify project from the latest template.

This command will:
1. Check that required tools are installed (git is optional)
2. Let you choose your AI assistant
3. Download the appropriate template from GitHub
4. Extract the template to a new project directory or current directory
5. Initialize a fresh git repository (if not --no-git and no existing repo)
6. Optionally set up AI assistant commands

Examples:
specify init my-project
specify init my-project --ai claude
Expand Down Expand Up @@ -1052,8 +1052,8 @@ def init(
# Create options dict for selection (agent_key: display_name)
ai_choices = {key: config["name"] for key, config in AGENT_CONFIG.items()}
selected_ai = select_with_arrows(
ai_choices,
"Choose your AI assistant:",
ai_choices,
"Choose your AI assistant:",
"copilot"
)

Expand Down Expand Up @@ -1165,7 +1165,7 @@ def init(

console.print(tracker.render())
console.print("\n[bold green]Project ready.[/bold green]")

# Show git error details if initialization failed
if git_error_message:
console.print()
Expand Down Expand Up @@ -1213,7 +1213,7 @@ def init(
cmd = f"setx CODEX_HOME {quoted_path}"
else: # Unix-like systems
cmd = f"export CODEX_HOME={quoted_path}"

steps_lines.append(f"{step_num}. Set [cyan]CODEX_HOME[/cyan] environment variable before running Codex: [cyan]{cmd}[/cyan]")
step_num += 1

Expand Down Expand Up @@ -1287,9 +1287,9 @@ def version():
"""Display version and system information."""
import platform
import importlib.metadata

show_banner()

# Get CLI version from package metadata
cli_version = "unknown"
try:
Expand All @@ -1305,15 +1305,15 @@ def version():
cli_version = data.get("project", {}).get("version", "unknown")
except Exception:
pass

# Fetch latest template release version
repo_owner = "github"
repo_owner = "young-hwang"
repo_name = "spec-kit"
api_url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/releases/latest"

template_version = "unknown"
release_date = "unknown"

try:
response = client.get(
api_url,
Expand Down
8 changes: 8 additions & 0 deletions templates/commands/analyze.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ Ask the user: "Would you like me to suggest concrete remediation edits for the t

## Operating Principles

### Language Requirements

**ALL analysis output MUST be written in Korean (한글)**
- Section headings should remain in English for template compatibility
- All descriptions, findings, recommendations, and summaries must be in Korean
- Technical terms can be kept in English when appropriate (e.g., API, CRITICAL, HIGH)
- Report tables should have Korean column headers and content

### Context Efficiency

- **Minimal high-signal tokens**: Focus on actionable findings, not exhaustive documentation
Expand Down
9 changes: 9 additions & 0 deletions templates/commands/checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ scripts:
ps: scripts/powershell/check-prerequisites.ps1 -Json
---

## Language Requirements

**ALL checklist content MUST be written in Korean (한글)**
- Section headings in the checklist file should remain in English for template compatibility
- All checklist items, questions, and descriptions must be in Korean
- Technical terms can be kept in English when appropriate (e.g., API, UX, NFR)
- Quality dimension markers remain in English (e.g., [Completeness], [Clarity], [Gap])
- Spec section references remain as-is (e.g., [Spec §FR-1])

## Checklist Purpose: "Unit Tests for English"

**CRITICAL CONCEPT**: Checklists are **UNIT TESTS FOR REQUIREMENTS WRITING** - they validate the quality, clarity, and completeness of requirements in a given domain.
Expand Down
9 changes: 9 additions & 0 deletions templates/commands/clarify.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ $ARGUMENTS

You **MUST** consider the user input before proceeding (if not empty).

## Language Requirements

**ALL clarification content MUST be written in Korean (한글)**
- Section headings in the spec file should remain in English for template compatibility
- All questions, answers, clarifications, and spec updates must be in Korean
- Technical terms can be kept in English when appropriate (e.g., API, OAuth, JWT)
- Quality dimension markers and status labels can remain in English (e.g., Clear, Partial, Missing)
- Markdown table headers and content should be in Korean

## Outline

Goal: Detect and reduce ambiguity or missing decision points in the active feature specification and record the clarifications directly in the spec file.
Expand Down
10 changes: 10 additions & 0 deletions templates/commands/constitution.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ $ARGUMENTS

You **MUST** consider the user input before proceeding (if not empty).

## Language Requirements

**ALL user interaction and reporting MUST be in Korean (한글)**
- Questions to the user must be in Korean
- Sync Impact Report must be in Korean
- Final summary to the user must be in Korean
- The constitution file itself remains in English (it's a technical template)
- Technical terms and identifiers remain in English
- Comments in the constitution can be in Korean if added for clarification

## Outline

You are updating the project constitution at `/memory/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts.
Expand Down
10 changes: 10 additions & 0 deletions templates/commands/implement.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ $ARGUMENTS

You **MUST** consider the user input before proceeding (if not empty).

## Language Requirements

**ALL user interaction and reporting MUST be in Korean (한글)**
- Progress reports must be in Korean
- Status tables and summaries must be in Korean
- Questions to the user must be in Korean
- Error messages and suggestions must be in Korean
- Code and technical identifiers remain in English
- Technical terms can be kept in English when appropriate (e.g., API, TDD, CLI)

## Outline

1. Run `{SCRIPT}` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
Expand Down
9 changes: 9 additions & 0 deletions templates/commands/plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ $ARGUMENTS

You **MUST** consider the user input before proceeding (if not empty).

## Language Requirements

**ALL planning content MUST be written in Korean (한글)**
- Section headings in planning documents should remain in English for template compatibility
- All descriptions, decisions, rationales, and technical context must be in Korean
- Technical terms can be kept in English when appropriate (e.g., API, REST, GraphQL)
- File paths and code identifiers remain in English
- User interaction and reporting must be in Korean

## Outline

1. **Setup**: Run `{SCRIPT}` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
Expand Down
10 changes: 9 additions & 1 deletion templates/commands/specify.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,13 +199,21 @@ Given that feature description, do this:

## General Guidelines

### Language Requirements

**ALL specification content MUST be written in Korean (한글)**
- Section headings should remain in English for template compatibility
- All descriptions, requirements, scenarios, and criteria must be in Korean
- Technical terms can be kept in English when appropriate (e.g., API, OAuth, JWT)

## Quick Guidelines

- Focus on **WHAT** users need and **WHY**.
- Avoid HOW to implement (no tech stack, APIs, code structure).
- Written for business stakeholders, not developers.
- DO NOT create any checklists that are embedded in the spec. That will be a separate command.

- **Write all content in Korean (한글)** - only section headings remain in English

### Section Requirements

- **Mandatory sections**: Must be completed for every feature
Expand Down
10 changes: 10 additions & 0 deletions templates/commands/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ $ARGUMENTS

You **MUST** consider the user input before proceeding (if not empty).

## Language Requirements

**ALL task content MUST be written in Korean (한글)**
- Section headings in tasks.md should remain in English for template compatibility
- All task descriptions, goals, and criteria must be in Korean
- Technical terms can be kept in English when appropriate (e.g., API, TDD, MVP)
- File paths and code identifiers remain in English
- Task IDs and labels remain in English (e.g., T001, [P], [US1])
- User interaction and reporting must be in Korean

## Outline

1. **Setup**: Run `{SCRIPT}` from repo root and parse FEATURE_DIR and AVAILABLE_DOCS list. All paths must be absolute. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
Expand Down
Loading