diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index 48678282e1..c3dd66792b 100755 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -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 diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 1dedb31949..4468e73dbd 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -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") @@ -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") @@ -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: @@ -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 @@ -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" @@ -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 """ @@ -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 """ @@ -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 @@ -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]) """ @@ -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 @@ -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) @@ -957,7 +957,7 @@ 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 @@ -965,7 +965,7 @@ def init( 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 @@ -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" ) @@ -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() @@ -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 @@ -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: @@ -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, diff --git a/templates/commands/analyze.md b/templates/commands/analyze.md index 827d4e4caf..134e323b8b 100644 --- a/templates/commands/analyze.md +++ b/templates/commands/analyze.md @@ -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 diff --git a/templates/commands/checklist.md b/templates/commands/checklist.md index e32a2c843b..ff126a3127 100644 --- a/templates/commands/checklist.md +++ b/templates/commands/checklist.md @@ -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. diff --git a/templates/commands/clarify.md b/templates/commands/clarify.md index 4de842aa60..33fffc76a3 100644 --- a/templates/commands/clarify.md +++ b/templates/commands/clarify.md @@ -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. diff --git a/templates/commands/constitution.md b/templates/commands/constitution.md index cf81f08c2f..6a85a0abd1 100644 --- a/templates/commands/constitution.md +++ b/templates/commands/constitution.md @@ -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. diff --git a/templates/commands/implement.md b/templates/commands/implement.md index 39abb1e6c8..86718a3e7e 100644 --- a/templates/commands/implement.md +++ b/templates/commands/implement.md @@ -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"). diff --git a/templates/commands/plan.md b/templates/commands/plan.md index 147da0afa0..e8d49280e5 100644 --- a/templates/commands/plan.md +++ b/templates/commands/plan.md @@ -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"). diff --git a/templates/commands/specify.md b/templates/commands/specify.md index 3c952d683e..fdb6208bac 100644 --- a/templates/commands/specify.md +++ b/templates/commands/specify.md @@ -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 diff --git a/templates/commands/tasks.md b/templates/commands/tasks.md index d69d43763e..d45f61b963 100644 --- a/templates/commands/tasks.md +++ b/templates/commands/tasks.md @@ -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"). diff --git a/templates/commands/taskstoissues.md b/templates/commands/taskstoissues.md index d6aa3bbf55..5743f99389 100644 --- a/templates/commands/taskstoissues.md +++ b/templates/commands/taskstoissues.md @@ -14,6 +14,15 @@ $ARGUMENTS You **MUST** consider the user input before proceeding (if not empty). +## Language Requirements + +**ALL GitHub issue content MUST be written in Korean (한글)** +- Issue titles must be in Korean +- Issue descriptions must be in Korean +- Technical terms can be kept in English when appropriate (e.g., API, GitHub) +- File paths and code identifiers remain in English +- User interaction and reporting must be in Korean + ## 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").