From 681dc46af9baa707d4de3dae1ad706b9756a9de4 Mon Sep 17 00:00:00 2001 From: KhawarHabibKhan Date: Fri, 13 Mar 2026 22:02:57 +0500 Subject: [PATCH 1/8] feat: add specify status command with project info, agent detection, and feature detection --- src/specify_cli/__init__.py | 136 ++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index dac7eaa54..c5a4b6c0a 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1775,6 +1775,142 @@ def version(): console.print() +@app.command() +def status(): + """Show current project status and SDD workflow progress.""" + show_banner() + + project_root = Path.cwd() + + # Check if we're in a spec-kit project + specify_dir = project_root / ".specify" + if not specify_dir.exists(): + console.print("[red]Error:[/red] Not a spec-kit project (no .specify/ directory)") + console.print("Run [cyan]specify init[/cyan] first to create a project, or cd into an existing one.") + raise typer.Exit(1) + + project_name = project_root.name + + # --- Detect AI agent(s) by scanning for known agent folders --- + detected_agents = [] + for agent_key, agent_config in AGENT_CONFIG.items(): + if agent_key == "generic": + continue + folder = agent_config.get("folder") + if folder and (project_root / folder.rstrip("/")).is_dir(): + commands_subdir = agent_config.get("commands_subdir", "commands") + commands_dir = project_root / folder.rstrip("/") / commands_subdir + has_commands = commands_dir.is_dir() and any(commands_dir.iterdir()) + detected_agents.append({ + "key": agent_key, + "name": agent_config["name"], + "folder": folder, + "has_commands": has_commands, + }) + + # --- Detect script type --- + script_type = None + if (specify_dir / "scripts" / "bash").is_dir(): + script_type = "sh" + if (specify_dir / "scripts" / "powershell").is_dir(): + script_type = "ps" if script_type is None else "sh + ps" + + # --- Detect current feature --- + current_branch = None + has_git = False + + # 1. Check SPECIFY_FEATURE env var + env_feature = os.environ.get("SPECIFY_FEATURE", "").strip() + if env_feature: + current_branch = env_feature + + # 2. Try git branch + if not current_branch: + try: + result = subprocess.run( + ["git", "rev-parse", "--abbrev-ref", "HEAD"], + capture_output=True, text=True, timeout=5, + cwd=str(project_root), + ) + if result.returncode == 0: + has_git = True + current_branch = result.stdout.strip() + except (FileNotFoundError, subprocess.TimeoutExpired): + pass + + # 3. Fallback: scan specs/ for highest-numbered directory + if not current_branch or not current_branch[0:3].isdigit(): + specs_dir = project_root / "specs" + if specs_dir.is_dir(): + highest_num = 0 + latest_feature = None + for d in specs_dir.iterdir(): + if d.is_dir() and len(d.name) >= 4 and d.name[:3].isdigit() and d.name[3] == "-": + num = int(d.name[:3]) + if num > highest_num: + highest_num = num + latest_feature = d.name + if latest_feature and (not current_branch or current_branch in ("main", "master")): + current_branch = latest_feature + + # --- Resolve feature directory (prefix-based matching like common.sh) --- + feature_dir = None + if current_branch and len(current_branch) >= 4 and current_branch[:3].isdigit() and current_branch[3] == "-": + prefix = current_branch[:3] + specs_dir = project_root / "specs" + if specs_dir.is_dir(): + matches = [d for d in specs_dir.iterdir() if d.is_dir() and d.name.startswith(f"{prefix}-")] + if len(matches) == 1: + feature_dir = matches[0] + elif len(matches) > 1: + # Try exact match first + exact = specs_dir / current_branch + if exact.is_dir(): + feature_dir = exact + else: + feature_dir = matches[0] # Use first match + + # --- Build output --- + info_table = Table(show_header=False, box=None, padding=(0, 2)) + info_table.add_column("Key", style="cyan", justify="right", min_width=16) + info_table.add_column("Value", style="white") + + info_table.add_row("Project", f"[bold]{project_name}[/bold]") + + if detected_agents: + for i, agent in enumerate(detected_agents): + label = "AI Agent" if i == 0 else "" + cmd_status = "[green]commands present[/green]" if agent["has_commands"] else "[yellow]no commands[/yellow]" + info_table.add_row(label, f"{agent['name']} ({agent['folder']}) {cmd_status}") + else: + info_table.add_row("AI Agent", "[yellow]none detected[/yellow]") + + if script_type: + info_table.add_row("Script Type", script_type) + + if has_git: + info_table.add_row("Git Branch", current_branch or "[dim]unknown[/dim]") + else: + if env_feature: + info_table.add_row("Feature", f"{env_feature} [dim](from SPECIFY_FEATURE)[/dim]") + else: + info_table.add_row("Git", "[yellow]not available[/yellow]") + + if feature_dir: + info_table.add_row("Feature Dir", f"specs/{feature_dir.name}/") + elif current_branch and current_branch not in ("main", "master"): + info_table.add_row("Feature Dir", f"[yellow]not found for {current_branch}[/yellow]") + + panel = Panel( + info_table, + title="[bold cyan]Specify Project Status[/bold cyan]", + border_style="cyan", + padding=(1, 2), + ) + console.print(panel) + console.print() + + # ===== Extension Commands ===== extension_app = typer.Typer( From 3be36f87593db6c76b85a904893458600c6fc72e Mon Sep 17 00:00:00 2001 From: KhawarHabibKhan Date: Fri, 13 Mar 2026 22:05:03 +0500 Subject: [PATCH 2/8] feat: add SDD artifacts check and task progress parsing to specify status --- src/specify_cli/__init__.py | 101 +++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index c5a4b6c0a..5b53f1bc4 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1908,7 +1908,106 @@ def status(): padding=(1, 2), ) console.print(panel) - console.print() + + # --- SDD Artifacts & Task Progress --- + if feature_dir and feature_dir.is_dir(): + console.print(f"[bold cyan] Current Feature:[/bold cyan] {feature_dir.name}") + console.print(f" {'─' * 40}") + + # Define all SDD artifacts to check + artifacts = [ + ("spec.md", feature_dir / "spec.md"), + ("plan.md", feature_dir / "plan.md"), + ("tasks.md", feature_dir / "tasks.md"), + ("research.md", feature_dir / "research.md"), + ("data-model.md", feature_dir / "data-model.md"), + ("quickstart.md", feature_dir / "quickstart.md"), + ] + # Directory-based artifacts + contracts_dir = feature_dir / "contracts" + checklists_dir = feature_dir / "checklists" + + # Parse task progress from tasks.md if it exists + tasks_file = feature_dir / "tasks.md" + tasks_completed = 0 + tasks_total = 0 + if tasks_file.is_file(): + try: + tasks_content = tasks_file.read_text(encoding="utf-8") + import re + for line in tasks_content.splitlines(): + stripped = line.strip() + if re.match(r"^-\s+\[([ xX])\]", stripped): + tasks_total += 1 + if re.match(r"^-\s+\[[xX]\]", stripped): + tasks_completed += 1 + except OSError: + pass + + # Parse checklist progress if checklists/ exists + checklist_count = 0 + checklists_all_pass = True + if checklists_dir.is_dir(): + for cl_file in checklists_dir.iterdir(): + if cl_file.is_file() and cl_file.suffix == ".md": + checklist_count += 1 + try: + cl_content = cl_file.read_text(encoding="utf-8") + for line in cl_content.splitlines(): + stripped = line.strip() + if re.match(r"^-\s+\[ \]", stripped): + checklists_all_pass = False + break + except OSError: + pass + + # Display artifacts with status + console.print() + console.print(" [bold]Artifacts:[/bold]") + for artifact_name, artifact_path in artifacts: + if artifact_path.is_file(): + icon = "[green]✓[/green]" + extra = "" + # Add task progress info for tasks.md + if artifact_name == "tasks.md" and tasks_total > 0: + pct = int(tasks_completed / tasks_total * 100) + if tasks_completed == tasks_total: + extra = f" [green]{tasks_completed}/{tasks_total} completed (100%)[/green]" + else: + extra = f" [yellow]{tasks_completed}/{tasks_total} completed ({pct}%)[/yellow]" + console.print(f" {icon} {artifact_name}{extra}") + else: + console.print(f" [dim]✗ {artifact_name}[/dim]") + + # Contracts directory + has_contracts = contracts_dir.is_dir() and any(contracts_dir.iterdir()) + if has_contracts: + contract_files = len([f for f in contracts_dir.iterdir() if f.is_file()]) + console.print(f" [green]✓[/green] contracts/ [dim]{contract_files} file(s)[/dim]") + else: + console.print(f" [dim]✗ contracts/[/dim]") + + # Checklists directory + if checklist_count > 0: + if checklists_all_pass: + console.print(f" [green]✓[/green] checklists/ [green]{checklist_count} checklist(s), all passing[/green]") + else: + console.print(f" [yellow]✓[/yellow] checklists/ [yellow]{checklist_count} checklist(s), some incomplete[/yellow]") + else: + console.print(f" [dim]✗ checklists/[/dim]") + + console.print() + + elif current_branch and current_branch not in ("main", "master"): + console.print(f"\n [yellow]No feature directory found for branch '{current_branch}'[/yellow]") + console.print(f" [dim]Run /speckit.specify to create a feature.[/dim]\n") + else: + specs_dir = project_root / "specs" + if specs_dir.is_dir() and any(specs_dir.iterdir()): + feature_count = len([d for d in specs_dir.iterdir() if d.is_dir()]) + console.print(f"\n [dim]{feature_count} feature(s) in specs/ — switch to a feature branch to see details.[/dim]\n") + else: + console.print(f"\n [dim]No features created yet. Run /speckit.specify to start.[/dim]\n") # ===== Extension Commands ===== From 1afe3c52af3485b1e73cd3d852311c1e71fbf56c Mon Sep 17 00:00:00 2001 From: KhawarHabibKhan Date: Fri, 13 Mar 2026 22:07:01 +0500 Subject: [PATCH 3/8] feat: add workflow phase detection and extensions summary to specify status --- src/specify_cli/__init__.py | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 5b53f1bc4..faccaa00e 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1996,6 +1996,30 @@ def status(): else: console.print(f" [dim]✗ checklists/[/dim]") + # --- Workflow Phase Detection --- + has_spec = (feature_dir / "spec.md").is_file() + has_plan = (feature_dir / "plan.md").is_file() + has_tasks = (feature_dir / "tasks.md").is_file() + all_tasks_done = has_tasks and tasks_total > 0 and tasks_completed == tasks_total + + if all_tasks_done: + phase_label = "[bold green]Complete[/bold green]" + phase_hint = "All tasks done. Review your implementation." + elif has_tasks: + phase_label = "[bold yellow]Implement[/bold yellow]" + phase_hint = "Ready for [cyan]/speckit.implement[/cyan]" + elif has_plan: + phase_label = "[bold yellow]Tasks[/bold yellow]" + phase_hint = "Ready for [cyan]/speckit.tasks[/cyan]" + elif has_spec: + phase_label = "[bold yellow]Plan[/bold yellow]" + phase_hint = "Ready for [cyan]/speckit.clarify[/cyan] or [cyan]/speckit.plan[/cyan]" + else: + phase_label = "[bold red]Not Started[/bold red]" + phase_hint = "Run [cyan]/speckit.specify[/cyan] to create a spec" + + console.print(f" [bold]Phase:[/bold] {phase_label}") + console.print(f" [dim]{phase_hint}[/dim]") console.print() elif current_branch and current_branch not in ("main", "master"): @@ -2009,6 +2033,37 @@ def status(): else: console.print(f"\n [dim]No features created yet. Run /speckit.specify to start.[/dim]\n") + # --- Extensions Summary --- + extensions_dir = specify_dir / "extensions" + installed_count = 0 + if extensions_dir.is_dir(): + try: + from .extensions import ExtensionManager + manager = ExtensionManager(project_root) + installed_count = len(manager.list_installed()) + except Exception: + pass + + available_count = 0 + try: + from .extensions import ExtensionCatalog + catalog = ExtensionCatalog(project_root) + available_count = len(catalog.search()) + except Exception: + pass + + ext_parts = [] + ext_parts.append(f"{installed_count} installed") + if available_count > 0: + ext_parts.append(f"{available_count} available in catalog") + else: + ext_parts.append("catalog unavailable") + + console.print(f" [bold]Extensions:[/bold] {', '.join(ext_parts)}") + if installed_count == 0 and available_count > 0: + console.print(f" [dim]Run [cyan]specify extension search[/cyan] to browse available extensions.[/dim]") + console.print() + # ===== Extension Commands ===== From 7466edc178282b5322faf10294c0c5022131c994 Mon Sep 17 00:00:00 2001 From: KhawarHabibKhan Date: Mon, 16 Mar 2026 16:39:54 +0500 Subject: [PATCH 4/8] Revert "feat: add workflow phase detection and extensions summary to specify status" This reverts commit 1afe3c52af3485b1e73cd3d852311c1e71fbf56c. --- src/specify_cli/__init__.py | 55 ------------------------------------- 1 file changed, 55 deletions(-) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index faccaa00e..5b53f1bc4 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1996,30 +1996,6 @@ def status(): else: console.print(f" [dim]✗ checklists/[/dim]") - # --- Workflow Phase Detection --- - has_spec = (feature_dir / "spec.md").is_file() - has_plan = (feature_dir / "plan.md").is_file() - has_tasks = (feature_dir / "tasks.md").is_file() - all_tasks_done = has_tasks and tasks_total > 0 and tasks_completed == tasks_total - - if all_tasks_done: - phase_label = "[bold green]Complete[/bold green]" - phase_hint = "All tasks done. Review your implementation." - elif has_tasks: - phase_label = "[bold yellow]Implement[/bold yellow]" - phase_hint = "Ready for [cyan]/speckit.implement[/cyan]" - elif has_plan: - phase_label = "[bold yellow]Tasks[/bold yellow]" - phase_hint = "Ready for [cyan]/speckit.tasks[/cyan]" - elif has_spec: - phase_label = "[bold yellow]Plan[/bold yellow]" - phase_hint = "Ready for [cyan]/speckit.clarify[/cyan] or [cyan]/speckit.plan[/cyan]" - else: - phase_label = "[bold red]Not Started[/bold red]" - phase_hint = "Run [cyan]/speckit.specify[/cyan] to create a spec" - - console.print(f" [bold]Phase:[/bold] {phase_label}") - console.print(f" [dim]{phase_hint}[/dim]") console.print() elif current_branch and current_branch not in ("main", "master"): @@ -2033,37 +2009,6 @@ def status(): else: console.print(f"\n [dim]No features created yet. Run /speckit.specify to start.[/dim]\n") - # --- Extensions Summary --- - extensions_dir = specify_dir / "extensions" - installed_count = 0 - if extensions_dir.is_dir(): - try: - from .extensions import ExtensionManager - manager = ExtensionManager(project_root) - installed_count = len(manager.list_installed()) - except Exception: - pass - - available_count = 0 - try: - from .extensions import ExtensionCatalog - catalog = ExtensionCatalog(project_root) - available_count = len(catalog.search()) - except Exception: - pass - - ext_parts = [] - ext_parts.append(f"{installed_count} installed") - if available_count > 0: - ext_parts.append(f"{available_count} available in catalog") - else: - ext_parts.append("catalog unavailable") - - console.print(f" [bold]Extensions:[/bold] {', '.join(ext_parts)}") - if installed_count == 0 and available_count > 0: - console.print(f" [dim]Run [cyan]specify extension search[/cyan] to browse available extensions.[/dim]") - console.print() - # ===== Extension Commands ===== From e12bfc0da2bf08e2338c74582208f93de0255405 Mon Sep 17 00:00:00 2001 From: KhawarHabibKhan Date: Mon, 16 Mar 2026 16:39:54 +0500 Subject: [PATCH 5/8] Revert "feat: add SDD artifacts check and task progress parsing to specify status" This reverts commit 3be36f87593db6c76b85a904893458600c6fc72e. --- src/specify_cli/__init__.py | 101 +----------------------------------- 1 file changed, 1 insertion(+), 100 deletions(-) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 5b53f1bc4..c5a4b6c0a 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1908,106 +1908,7 @@ def status(): padding=(1, 2), ) console.print(panel) - - # --- SDD Artifacts & Task Progress --- - if feature_dir and feature_dir.is_dir(): - console.print(f"[bold cyan] Current Feature:[/bold cyan] {feature_dir.name}") - console.print(f" {'─' * 40}") - - # Define all SDD artifacts to check - artifacts = [ - ("spec.md", feature_dir / "spec.md"), - ("plan.md", feature_dir / "plan.md"), - ("tasks.md", feature_dir / "tasks.md"), - ("research.md", feature_dir / "research.md"), - ("data-model.md", feature_dir / "data-model.md"), - ("quickstart.md", feature_dir / "quickstart.md"), - ] - # Directory-based artifacts - contracts_dir = feature_dir / "contracts" - checklists_dir = feature_dir / "checklists" - - # Parse task progress from tasks.md if it exists - tasks_file = feature_dir / "tasks.md" - tasks_completed = 0 - tasks_total = 0 - if tasks_file.is_file(): - try: - tasks_content = tasks_file.read_text(encoding="utf-8") - import re - for line in tasks_content.splitlines(): - stripped = line.strip() - if re.match(r"^-\s+\[([ xX])\]", stripped): - tasks_total += 1 - if re.match(r"^-\s+\[[xX]\]", stripped): - tasks_completed += 1 - except OSError: - pass - - # Parse checklist progress if checklists/ exists - checklist_count = 0 - checklists_all_pass = True - if checklists_dir.is_dir(): - for cl_file in checklists_dir.iterdir(): - if cl_file.is_file() and cl_file.suffix == ".md": - checklist_count += 1 - try: - cl_content = cl_file.read_text(encoding="utf-8") - for line in cl_content.splitlines(): - stripped = line.strip() - if re.match(r"^-\s+\[ \]", stripped): - checklists_all_pass = False - break - except OSError: - pass - - # Display artifacts with status - console.print() - console.print(" [bold]Artifacts:[/bold]") - for artifact_name, artifact_path in artifacts: - if artifact_path.is_file(): - icon = "[green]✓[/green]" - extra = "" - # Add task progress info for tasks.md - if artifact_name == "tasks.md" and tasks_total > 0: - pct = int(tasks_completed / tasks_total * 100) - if tasks_completed == tasks_total: - extra = f" [green]{tasks_completed}/{tasks_total} completed (100%)[/green]" - else: - extra = f" [yellow]{tasks_completed}/{tasks_total} completed ({pct}%)[/yellow]" - console.print(f" {icon} {artifact_name}{extra}") - else: - console.print(f" [dim]✗ {artifact_name}[/dim]") - - # Contracts directory - has_contracts = contracts_dir.is_dir() and any(contracts_dir.iterdir()) - if has_contracts: - contract_files = len([f for f in contracts_dir.iterdir() if f.is_file()]) - console.print(f" [green]✓[/green] contracts/ [dim]{contract_files} file(s)[/dim]") - else: - console.print(f" [dim]✗ contracts/[/dim]") - - # Checklists directory - if checklist_count > 0: - if checklists_all_pass: - console.print(f" [green]✓[/green] checklists/ [green]{checklist_count} checklist(s), all passing[/green]") - else: - console.print(f" [yellow]✓[/yellow] checklists/ [yellow]{checklist_count} checklist(s), some incomplete[/yellow]") - else: - console.print(f" [dim]✗ checklists/[/dim]") - - console.print() - - elif current_branch and current_branch not in ("main", "master"): - console.print(f"\n [yellow]No feature directory found for branch '{current_branch}'[/yellow]") - console.print(f" [dim]Run /speckit.specify to create a feature.[/dim]\n") - else: - specs_dir = project_root / "specs" - if specs_dir.is_dir() and any(specs_dir.iterdir()): - feature_count = len([d for d in specs_dir.iterdir() if d.is_dir()]) - console.print(f"\n [dim]{feature_count} feature(s) in specs/ — switch to a feature branch to see details.[/dim]\n") - else: - console.print(f"\n [dim]No features created yet. Run /speckit.specify to start.[/dim]\n") + console.print() # ===== Extension Commands ===== From e14b296aee3f7d258869098e00dc0b008a496d4b Mon Sep 17 00:00:00 2001 From: KhawarHabibKhan Date: Mon, 16 Mar 2026 16:39:54 +0500 Subject: [PATCH 6/8] Revert "feat: add specify status command with project info, agent detection, and feature detection" This reverts commit 681dc46af9baa707d4de3dae1ad706b9756a9de4. --- src/specify_cli/__init__.py | 136 ------------------------------------ 1 file changed, 136 deletions(-) diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index c5a4b6c0a..dac7eaa54 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -1775,142 +1775,6 @@ def version(): console.print() -@app.command() -def status(): - """Show current project status and SDD workflow progress.""" - show_banner() - - project_root = Path.cwd() - - # Check if we're in a spec-kit project - specify_dir = project_root / ".specify" - if not specify_dir.exists(): - console.print("[red]Error:[/red] Not a spec-kit project (no .specify/ directory)") - console.print("Run [cyan]specify init[/cyan] first to create a project, or cd into an existing one.") - raise typer.Exit(1) - - project_name = project_root.name - - # --- Detect AI agent(s) by scanning for known agent folders --- - detected_agents = [] - for agent_key, agent_config in AGENT_CONFIG.items(): - if agent_key == "generic": - continue - folder = agent_config.get("folder") - if folder and (project_root / folder.rstrip("/")).is_dir(): - commands_subdir = agent_config.get("commands_subdir", "commands") - commands_dir = project_root / folder.rstrip("/") / commands_subdir - has_commands = commands_dir.is_dir() and any(commands_dir.iterdir()) - detected_agents.append({ - "key": agent_key, - "name": agent_config["name"], - "folder": folder, - "has_commands": has_commands, - }) - - # --- Detect script type --- - script_type = None - if (specify_dir / "scripts" / "bash").is_dir(): - script_type = "sh" - if (specify_dir / "scripts" / "powershell").is_dir(): - script_type = "ps" if script_type is None else "sh + ps" - - # --- Detect current feature --- - current_branch = None - has_git = False - - # 1. Check SPECIFY_FEATURE env var - env_feature = os.environ.get("SPECIFY_FEATURE", "").strip() - if env_feature: - current_branch = env_feature - - # 2. Try git branch - if not current_branch: - try: - result = subprocess.run( - ["git", "rev-parse", "--abbrev-ref", "HEAD"], - capture_output=True, text=True, timeout=5, - cwd=str(project_root), - ) - if result.returncode == 0: - has_git = True - current_branch = result.stdout.strip() - except (FileNotFoundError, subprocess.TimeoutExpired): - pass - - # 3. Fallback: scan specs/ for highest-numbered directory - if not current_branch or not current_branch[0:3].isdigit(): - specs_dir = project_root / "specs" - if specs_dir.is_dir(): - highest_num = 0 - latest_feature = None - for d in specs_dir.iterdir(): - if d.is_dir() and len(d.name) >= 4 and d.name[:3].isdigit() and d.name[3] == "-": - num = int(d.name[:3]) - if num > highest_num: - highest_num = num - latest_feature = d.name - if latest_feature and (not current_branch or current_branch in ("main", "master")): - current_branch = latest_feature - - # --- Resolve feature directory (prefix-based matching like common.sh) --- - feature_dir = None - if current_branch and len(current_branch) >= 4 and current_branch[:3].isdigit() and current_branch[3] == "-": - prefix = current_branch[:3] - specs_dir = project_root / "specs" - if specs_dir.is_dir(): - matches = [d for d in specs_dir.iterdir() if d.is_dir() and d.name.startswith(f"{prefix}-")] - if len(matches) == 1: - feature_dir = matches[0] - elif len(matches) > 1: - # Try exact match first - exact = specs_dir / current_branch - if exact.is_dir(): - feature_dir = exact - else: - feature_dir = matches[0] # Use first match - - # --- Build output --- - info_table = Table(show_header=False, box=None, padding=(0, 2)) - info_table.add_column("Key", style="cyan", justify="right", min_width=16) - info_table.add_column("Value", style="white") - - info_table.add_row("Project", f"[bold]{project_name}[/bold]") - - if detected_agents: - for i, agent in enumerate(detected_agents): - label = "AI Agent" if i == 0 else "" - cmd_status = "[green]commands present[/green]" if agent["has_commands"] else "[yellow]no commands[/yellow]" - info_table.add_row(label, f"{agent['name']} ({agent['folder']}) {cmd_status}") - else: - info_table.add_row("AI Agent", "[yellow]none detected[/yellow]") - - if script_type: - info_table.add_row("Script Type", script_type) - - if has_git: - info_table.add_row("Git Branch", current_branch or "[dim]unknown[/dim]") - else: - if env_feature: - info_table.add_row("Feature", f"{env_feature} [dim](from SPECIFY_FEATURE)[/dim]") - else: - info_table.add_row("Git", "[yellow]not available[/yellow]") - - if feature_dir: - info_table.add_row("Feature Dir", f"specs/{feature_dir.name}/") - elif current_branch and current_branch not in ("main", "master"): - info_table.add_row("Feature Dir", f"[yellow]not found for {current_branch}[/yellow]") - - panel = Panel( - info_table, - title="[bold cyan]Specify Project Status[/bold cyan]", - border_style="cyan", - padding=(1, 2), - ) - console.print(panel) - console.print() - - # ===== Extension Commands ===== extension_app = typer.Typer( From c8e9f16cf9fb0eec1709c4063741ad364fea8bc4 Mon Sep 17 00:00:00 2001 From: KhawarHabibKhan Date: Mon, 16 Mar 2026 17:02:58 +0500 Subject: [PATCH 7/8] feat: add spec-kit-status extension to community catalog --- extensions/README.md | 1 + extensions/catalog.community.json | 32 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/extensions/README.md b/extensions/README.md index e8f1617e9..1f68cce5c 100644 --- a/extensions/README.md +++ b/extensions/README.md @@ -76,6 +76,7 @@ The following community-contributed extensions are available in [`catalog.commun | Cleanup Extension | Post-implementation quality gate that reviews changes, fixes small issues (scout rule), creates tasks for medium issues, and generates analysis for large issues | [spec-kit-cleanup](https://github.com/dsrednicki/spec-kit-cleanup) | | Fleet Orchestrator | Orchestrate a full feature lifecycle with human-in-the-loop gates across all SpecKit phases | [spec-kit-fleet](https://github.com/sharathsatish/spec-kit-fleet) | | Jira Integration | Create Jira Epics, Stories, and Issues from spec-kit specifications and task breakdowns with configurable hierarchy and custom field support | [spec-kit-jira](https://github.com/mbachorik/spec-kit-jira) | +| Project Status | Show current SDD workflow progress — active feature, artifact status, task completion, workflow phase, and extensions summary | [spec-kit-status](https://github.com/KhawarHabibKhan/spec-kit-status) | | Ralph Loop | Autonomous implementation loop using AI agent CLI | [spec-kit-ralph](https://github.com/Rubiss/spec-kit-ralph) | | Retrospective Extension | Post-implementation retrospective with spec adherence scoring, drift analysis, and human-gated spec updates | [spec-kit-retrospective](https://github.com/emi-dm/spec-kit-retrospective) | | Review Extension | Post-implementation comprehensive code review with specialized agents for code quality, comments, tests, error handling, type design, and simplification | [spec-kit-review](https://github.com/ismaelJimenez/spec-kit-review) | diff --git a/extensions/catalog.community.json b/extensions/catalog.community.json index 759bd10d8..485832ac7 100644 --- a/extensions/catalog.community.json +++ b/extensions/catalog.community.json @@ -361,6 +361,38 @@ "stars": 0, "created_at": "2026-03-03T00:00:00Z", "updated_at": "2026-03-03T00:00:00Z" + }, + "status": { + "name": "Project Status", + "id": "status", + "description": "Show current SDD workflow progress — active feature, artifact status, task completion, workflow phase, and extensions summary.", + "author": "KhawarHabibKhan", + "version": "1.0.0", + "download_url": "https://github.com/KhawarHabibKhan/spec-kit-status/archive/refs/tags/v1.0.0.zip", + "repository": "https://github.com/KhawarHabibKhan/spec-kit-status", + "homepage": "https://github.com/KhawarHabibKhan/spec-kit-status", + "documentation": "https://github.com/KhawarHabibKhan/spec-kit-status/blob/main/README.md", + "changelog": "https://github.com/KhawarHabibKhan/spec-kit-status/blob/main/CHANGELOG.md", + "license": "MIT", + "requires": { + "speckit_version": ">=0.1.0" + }, + "provides": { + "commands": 1, + "hooks": 0 + }, + "tags": [ + "status", + "workflow", + "progress", + "feature-tracking", + "task-progress" + ], + "verified": false, + "downloads": 0, + "stars": 0, + "created_at": "2026-03-16T00:00:00Z", + "updated_at": "2026-03-16T00:00:00Z" } } } From 2256f53456b5b263f5f41e0721f9a6b62d30fdf9 Mon Sep 17 00:00:00 2001 From: KhawarHabibKhan <132604863+KhawarHabibKhan@users.noreply.github.com> Date: Mon, 16 Mar 2026 19:08:09 +0500 Subject: [PATCH 8/8] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- extensions/catalog.community.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/catalog.community.json b/extensions/catalog.community.json index 7362999cd..655373569 100644 --- a/extensions/catalog.community.json +++ b/extensions/catalog.community.json @@ -1,6 +1,6 @@ { "schema_version": "1.0", - "updated_at": "2026-03-13T12:00:00Z", + "updated_at": "2026-03-16T00:00:00Z", "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json", "extensions": { "azure-devops": {