mirror of
https://github.com/github/spec-kit.git
synced 2026-02-01 13:33:37 +00:00
Compare commits
30 Commits
v0.0.77
...
copilot/st
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52394c6447 | ||
|
|
dafab39483 | ||
|
|
09274437fc | ||
|
|
5f1fc6b445 | ||
|
|
779e1f8afd | ||
|
|
177dcadd8c | ||
|
|
ba861cd165 | ||
|
|
926836e0fc | ||
|
|
af88930ffc | ||
|
|
89f5f9c0b9 | ||
|
|
9809b1a4ab | ||
|
|
7b536b578d | ||
|
|
7522eb3f9d | ||
|
|
d550634d8e | ||
|
|
72cb885eb7 | ||
|
|
a877af5575 | ||
|
|
2508d926c0 | ||
|
|
e77d99abd2 | ||
|
|
d4d3139d5f | ||
|
|
65f8787b48 | ||
|
|
9786e588b7 | ||
|
|
0ac76c8c7e | ||
|
|
115b4335d9 | ||
|
|
37e87c78a0 | ||
|
|
14a574a6a8 | ||
|
|
dbd1437aea | ||
|
|
317ae4dad9 | ||
|
|
8e9d25e9be | ||
|
|
c59be99dc4 | ||
|
|
15a5630047 |
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -1,4 +1,6 @@
|
||||
name: Lint
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
@@ -95,12 +95,32 @@ generate_commands() {
|
||||
{ echo "description = \"$description\""; echo; echo "prompt = \"\"\""; echo "$body"; echo "\"\"\""; } > "$output_dir/speckit.$name.$ext" ;;
|
||||
md)
|
||||
echo "$body" > "$output_dir/speckit.$name.$ext" ;;
|
||||
prompt.md)
|
||||
chatmode.md)
|
||||
echo "$body" > "$output_dir/speckit.$name.$ext" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
generate_copilot_prompts() {
|
||||
local chatmodes_dir=$1 prompts_dir=$2
|
||||
mkdir -p "$prompts_dir"
|
||||
|
||||
# Generate a .prompt.md file for each .chatmode.md file
|
||||
for chatmode_file in "$chatmodes_dir"/speckit.*.chatmode.md; do
|
||||
[[ -f "$chatmode_file" ]] || continue
|
||||
|
||||
local basename=$(basename "$chatmode_file" .chatmode.md)
|
||||
local prompt_file="$prompts_dir/${basename}.prompt.md"
|
||||
|
||||
# Create prompt file with agent frontmatter
|
||||
cat > "$prompt_file" <<EOF
|
||||
---
|
||||
agent: ${basename}
|
||||
---
|
||||
EOF
|
||||
done
|
||||
}
|
||||
|
||||
build_variant() {
|
||||
local agent=$1 script=$2
|
||||
local base_dir="$GENRELEASES_DIR/sdd-${agent}-package-${script}"
|
||||
@@ -146,8 +166,10 @@ build_variant() {
|
||||
generate_commands gemini toml "{{args}}" "$base_dir/.gemini/commands" "$script"
|
||||
[[ -f agent_templates/gemini/GEMINI.md ]] && cp agent_templates/gemini/GEMINI.md "$base_dir/GEMINI.md" ;;
|
||||
copilot)
|
||||
mkdir -p "$base_dir/.github/prompts"
|
||||
generate_commands copilot prompt.md "\$ARGUMENTS" "$base_dir/.github/prompts" "$script"
|
||||
mkdir -p "$base_dir/.github/chatmodes"
|
||||
generate_commands copilot chatmode.md "\$ARGUMENTS" "$base_dir/.github/chatmodes" "$script"
|
||||
# Generate companion prompt files
|
||||
generate_copilot_prompts "$base_dir/.github/chatmodes" "$base_dir/.github/prompts"
|
||||
# Create VS Code workspace settings
|
||||
mkdir -p "$base_dir/.vscode"
|
||||
[[ -f templates/vscode-settings.json ]] && cp templates/vscode-settings.json "$base_dir/.vscode/settings.json"
|
||||
|
||||
@@ -20,5 +20,8 @@
|
||||
"MD050": {
|
||||
"style": "asterisk"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ignores": [
|
||||
".genreleases/"
|
||||
]
|
||||
}
|
||||
17
AGENTS.md
17
AGENTS.md
@@ -33,7 +33,7 @@ Specify supports multiple AI agents by generating agent-specific command files a
|
||||
|-------|-----------|---------|----------|-------------|
|
||||
| **Claude Code** | `.claude/commands/` | Markdown | `claude` | Anthropic's Claude Code CLI |
|
||||
| **Gemini CLI** | `.gemini/commands/` | TOML | `gemini` | Google's Gemini CLI |
|
||||
| **GitHub Copilot** | `.github/prompts/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code |
|
||||
| **GitHub Copilot** | `.github/chatmodes/` | Markdown | N/A (IDE-based) | GitHub Copilot in VS Code |
|
||||
| **Cursor** | `.cursor/commands/` | Markdown | `cursor-agent` | Cursor CLI |
|
||||
| **Qwen Code** | `.qwen/commands/` | TOML | `qwen` | Alibaba's Qwen Code CLI |
|
||||
| **opencode** | `.opencode/command/` | Markdown | `opencode` | opencode CLI |
|
||||
@@ -325,6 +325,8 @@ Work within integrated development environments:
|
||||
|
||||
Used by: Claude, Cursor, opencode, Windsurf, Amazon Q Developer, Amp
|
||||
|
||||
**Standard format:**
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: "Command description"
|
||||
@@ -333,6 +335,17 @@ description: "Command description"
|
||||
Command content with {SCRIPT} and $ARGUMENTS placeholders.
|
||||
```
|
||||
|
||||
**GitHub Copilot Chat Mode format:**
|
||||
|
||||
```markdown
|
||||
---
|
||||
description: "Command description"
|
||||
mode: speckit.command-name
|
||||
---
|
||||
|
||||
Command content with {SCRIPT} and $ARGUMENTS placeholders.
|
||||
```
|
||||
|
||||
### TOML Format
|
||||
|
||||
Used by: Gemini, Qwen
|
||||
@@ -349,7 +362,7 @@ Command content with {SCRIPT} and {{args}} placeholders.
|
||||
|
||||
- **CLI agents**: Usually `.<agent-name>/commands/`
|
||||
- **IDE agents**: Follow IDE-specific patterns:
|
||||
- Copilot: `.github/prompts/`
|
||||
- Copilot: `.github/chatmodes/`
|
||||
- Cursor: `.cursor/commands/`
|
||||
- Windsurf: `.windsurf/workflows/`
|
||||
|
||||
|
||||
@@ -7,6 +7,14 @@ All notable changes to the Specify CLI and templates are documented here.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.0.21] - 2025-10-21
|
||||
|
||||
- Fixes [#975](https://github.com/github/spec-kit/issues/975) (thank you [@fgalarraga](https://github.com/fgalarraga)).
|
||||
- Adds support for Amp CLI.
|
||||
- Adds support for VS Code hand-offs and moves prompts to be full-fledged chat modes.
|
||||
- Adds support for `version` command (addresses [#811](https://github.com/github/spec-kit/issues/811) and [#486](https://github.com/github/spec-kit/issues/486), thank you [@mcasalaina](https://github.com/mcasalaina) and [@dentity007](https://github.com/dentity007)).
|
||||
- Adds support for rendering the rate limit errors from the CLI when encountered ([#970](https://github.com/github/spec-kit/issues/970), thank you [@psmman](https://github.com/psmman)).
|
||||
|
||||
## [0.0.20] - 2025-10-14
|
||||
|
||||
### Added
|
||||
|
||||
@@ -62,6 +62,29 @@ When working on spec-kit:
|
||||
3. Test script functionality in the `scripts/` directory
|
||||
4. Ensure memory files (`memory/constitution.md`) are updated if major process changes are made
|
||||
|
||||
### Testing template and command changes locally
|
||||
|
||||
Running `uv run specify init` pulls released packages, which won’t include your local changes.
|
||||
To test your templates, commands, and other changes locally, follow these steps:
|
||||
|
||||
1. **Create release packages**
|
||||
|
||||
Run the following command to generate the local packages:
|
||||
|
||||
```
|
||||
./.github/workflows/scripts/create-release-packages.sh v1.0.0
|
||||
```
|
||||
|
||||
2. **Copy the relevant package to your test project**
|
||||
|
||||
```
|
||||
cp -r .genreleases/sdd-copilot-package-sh/. <path-to-test-project>/
|
||||
```
|
||||
|
||||
3. **Open and test the agent**
|
||||
|
||||
Navigate to your test project folder and open the agent to verify your implementation.
|
||||
|
||||
## AI contributions in Spec Kit
|
||||
|
||||
> [!IMPORTANT]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "specify-cli"
|
||||
version = "0.0.20"
|
||||
version = "0.0.21"
|
||||
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
|
||||
@@ -87,17 +87,45 @@ cd "$REPO_ROOT"
|
||||
SPECS_DIR="$REPO_ROOT/specs"
|
||||
mkdir -p "$SPECS_DIR"
|
||||
|
||||
HIGHEST=0
|
||||
# Get highest number from specs directory
|
||||
HIGHEST_FROM_SPECS=0
|
||||
if [ -d "$SPECS_DIR" ]; then
|
||||
for dir in "$SPECS_DIR"/*; do
|
||||
[ -d "$dir" ] || continue
|
||||
dirname=$(basename "$dir")
|
||||
number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0")
|
||||
number=$((10#$number))
|
||||
if [ "$number" -gt "$HIGHEST" ]; then HIGHEST=$number; fi
|
||||
if [ "$number" -gt "$HIGHEST_FROM_SPECS" ]; then HIGHEST_FROM_SPECS=$number; fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Get highest number from branch names (both local and remote)
|
||||
HIGHEST_FROM_BRANCHES=0
|
||||
if [ "$HAS_GIT" = true ]; then
|
||||
# Get all branches (local and remote)
|
||||
branches=$(git branch -a 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$branches" ]; then
|
||||
while IFS= read -r branch; do
|
||||
# Clean branch name: remove leading markers and remote prefixes
|
||||
clean_branch=$(echo "$branch" | sed 's/^[* ]*//; s|^remotes/[^/]*/||')
|
||||
|
||||
# Extract feature number if branch matches pattern ###-*
|
||||
if echo "$clean_branch" | grep -q '^[0-9]\{3\}-'; then
|
||||
number=$(echo "$clean_branch" | grep -o '^[0-9]\{3\}' || echo "0")
|
||||
number=$((10#$number))
|
||||
if [ "$number" -gt "$HIGHEST_FROM_BRANCHES" ]; then HIGHEST_FROM_BRANCHES=$number; fi
|
||||
fi
|
||||
done <<< "$branches"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Use the highest number from either source
|
||||
HIGHEST=$HIGHEST_FROM_SPECS
|
||||
if [ "$HIGHEST_FROM_BRANCHES" -gt "$HIGHEST" ]; then
|
||||
HIGHEST=$HIGHEST_FROM_BRANCHES
|
||||
fi
|
||||
|
||||
NEXT=$((HIGHEST + 1))
|
||||
FEATURE_NUM=$(printf "%03d" "$NEXT")
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ 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"
|
||||
COPILOT_FILE="$REPO_ROOT/.github/chatmodes/copilot-instructions.md"
|
||||
CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc"
|
||||
QWEN_FILE="$REPO_ROOT/QWEN.md"
|
||||
AGENTS_FILE="$REPO_ROOT/AGENTS.md"
|
||||
|
||||
@@ -79,15 +79,40 @@ Set-Location $repoRoot
|
||||
$specsDir = Join-Path $repoRoot 'specs'
|
||||
New-Item -ItemType Directory -Path $specsDir -Force | Out-Null
|
||||
|
||||
$highest = 0
|
||||
# Get highest number from specs directory
|
||||
$highestFromSpecs = 0
|
||||
if (Test-Path $specsDir) {
|
||||
Get-ChildItem -Path $specsDir -Directory | ForEach-Object {
|
||||
if ($_.Name -match '^(\d{3})') {
|
||||
$num = [int]$matches[1]
|
||||
if ($num -gt $highest) { $highest = $num }
|
||||
if ($num -gt $highestFromSpecs) { $highestFromSpecs = $num }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Get highest number from branch names (both local and remote)
|
||||
$highestFromBranches = 0
|
||||
try {
|
||||
$branches = git branch -a 2>$null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
foreach ($branch in $branches) {
|
||||
# Clean branch name: remove leading markers and remote prefixes
|
||||
$cleanBranch = $branch.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', ''
|
||||
|
||||
# Extract feature number if branch matches pattern ###-*
|
||||
if ($cleanBranch -match '^(\d{3})-') {
|
||||
$num = [int]$matches[1]
|
||||
if ($num -gt $highestFromBranches) { $highestFromBranches = $num }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
# If git command fails, just continue with specs-only check
|
||||
Write-Verbose "Could not check Git branches: $_"
|
||||
}
|
||||
|
||||
# Use the highest number from either source
|
||||
$highest = [Math]::Max($highestFromSpecs, $highestFromBranches)
|
||||
$next = $highest + 1
|
||||
$featureNum = ('{0:000}' -f $next)
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ $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'
|
||||
$COPILOT_FILE = Join-Path $REPO_ROOT '.github/chatmodes/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'
|
||||
|
||||
@@ -51,6 +51,7 @@ from typer.core import TyperGroup
|
||||
import readchar
|
||||
import ssl
|
||||
import truststore
|
||||
from datetime import datetime, timezone
|
||||
|
||||
ssl_context = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
||||
client = httpx.Client(verify=ssl_context)
|
||||
@@ -64,6 +65,63 @@ def _github_auth_headers(cli_token: str | None = None) -> dict:
|
||||
token = _github_token(cli_token)
|
||||
return {"Authorization": f"Bearer {token}"} if token else {}
|
||||
|
||||
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")
|
||||
if "X-RateLimit-Remaining" in headers:
|
||||
info["remaining"] = headers.get("X-RateLimit-Remaining")
|
||||
if "X-RateLimit-Reset" in headers:
|
||||
reset_epoch = int(headers.get("X-RateLimit-Reset", "0"))
|
||||
if reset_epoch:
|
||||
reset_time = datetime.fromtimestamp(reset_epoch, tz=timezone.utc)
|
||||
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")
|
||||
try:
|
||||
info["retry_after_seconds"] = int(retry_after)
|
||||
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:
|
||||
lines.append(f" • Rate Limit: {rate_info['limit']} requests/hour")
|
||||
if "remaining" in rate_info:
|
||||
lines.append(f" • Remaining: {rate_info['remaining']}")
|
||||
if "reset_local" in rate_info:
|
||||
reset_str = rate_info["reset_local"].strftime("%Y-%m-%d %H:%M:%S %Z")
|
||||
lines.append(f" • Resets at: {reset_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
|
||||
AGENT_CONFIG = {
|
||||
"copilot": {
|
||||
@@ -577,10 +635,11 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri
|
||||
)
|
||||
status = response.status_code
|
||||
if status != 200:
|
||||
msg = f"GitHub API returned {status} for {api_url}"
|
||||
# Format detailed error message with rate-limit info
|
||||
error_msg = _format_rate_limit_error(status, response.headers, api_url)
|
||||
if debug:
|
||||
msg += f"\nResponse headers: {response.headers}\nBody (truncated 500): {response.text[:500]}"
|
||||
raise RuntimeError(msg)
|
||||
error_msg += f"\n\n[dim]Response body (truncated 500):[/dim]\n{response.text[:500]}"
|
||||
raise RuntimeError(error_msg)
|
||||
try:
|
||||
release_data = response.json()
|
||||
except ValueError as je:
|
||||
@@ -627,8 +686,11 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri
|
||||
headers=_github_auth_headers(github_token),
|
||||
) as response:
|
||||
if response.status_code != 200:
|
||||
body_sample = response.text[:400]
|
||||
raise RuntimeError(f"Download failed with {response.status_code}\nHeaders: {response.headers}\nBody (truncated): {body_sample}")
|
||||
# Handle rate-limiting on download as well
|
||||
error_msg = _format_rate_limit_error(response.status_code, response.headers, download_url)
|
||||
if debug:
|
||||
error_msg += f"\n\n[dim]Response body (truncated 400):[/dim]\n{response.text[:400]}"
|
||||
raise RuntimeError(error_msg)
|
||||
total_size = int(response.headers.get('content-length', 0))
|
||||
with open(zip_path, 'wb') as f:
|
||||
if total_size == 0:
|
||||
@@ -1202,6 +1264,85 @@ def check():
|
||||
if not any(agent_results.values()):
|
||||
console.print("[dim]Tip: Install an AI assistant for the best experience[/dim]")
|
||||
|
||||
@app.command()
|
||||
def version():
|
||||
"""Display version and system information."""
|
||||
import platform
|
||||
import importlib.metadata
|
||||
|
||||
show_banner()
|
||||
|
||||
# Get CLI version from package metadata
|
||||
cli_version = "unknown"
|
||||
try:
|
||||
cli_version = importlib.metadata.version("specify-cli")
|
||||
except Exception:
|
||||
# Fallback: try reading from pyproject.toml if running from source
|
||||
try:
|
||||
import tomllib
|
||||
pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
|
||||
if pyproject_path.exists():
|
||||
with open(pyproject_path, "rb") as f:
|
||||
data = tomllib.load(f)
|
||||
cli_version = data.get("project", {}).get("version", "unknown")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Fetch latest template release version
|
||||
repo_owner = "github"
|
||||
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,
|
||||
timeout=10,
|
||||
follow_redirects=True,
|
||||
headers=_github_auth_headers(),
|
||||
)
|
||||
if response.status_code == 200:
|
||||
release_data = response.json()
|
||||
template_version = release_data.get("tag_name", "unknown")
|
||||
# Remove 'v' prefix if present
|
||||
if template_version.startswith("v"):
|
||||
template_version = template_version[1:]
|
||||
release_date = release_data.get("published_at", "unknown")
|
||||
if release_date != "unknown":
|
||||
# Format the date nicely
|
||||
try:
|
||||
dt = datetime.fromisoformat(release_date.replace('Z', '+00:00'))
|
||||
release_date = dt.strftime("%Y-%m-%d")
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
info_table = Table(show_header=False, box=None, padding=(0, 2))
|
||||
info_table.add_column("Key", style="cyan", justify="right")
|
||||
info_table.add_column("Value", style="white")
|
||||
|
||||
info_table.add_row("CLI Version", cli_version)
|
||||
info_table.add_row("Template Version", template_version)
|
||||
info_table.add_row("Released", release_date)
|
||||
info_table.add_row("", "")
|
||||
info_table.add_row("Python", f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
|
||||
info_table.add_row("Platform", platform.system())
|
||||
info_table.add_row("Architecture", platform.machine())
|
||||
info_table.add_row("OS Version", platform.version())
|
||||
|
||||
panel = Panel(
|
||||
info_table,
|
||||
title="[bold cyan]Specify CLI Information[/bold cyan]",
|
||||
border_style="cyan",
|
||||
padding=(1, 2)
|
||||
)
|
||||
|
||||
console.print(panel)
|
||||
console.print()
|
||||
|
||||
def main():
|
||||
app()
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
---
|
||||
description: Identify underspecified areas in the current feature spec by asking up to 5 highly targeted clarification questions and encoding answers back into the spec.
|
||||
handoffs:
|
||||
- label: Build Technical Plan
|
||||
agent: speckit.plan
|
||||
prompt: Create a plan for the spec. I am building with...
|
||||
scripts:
|
||||
sh: scripts/bash/check-prerequisites.sh --json --paths-only
|
||||
ps: scripts/powershell/check-prerequisites.ps1 -Json -PathsOnly
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
---
|
||||
description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync
|
||||
description: Create or update the project constitution from interactive or provided principle inputs, ensuring all dependent templates stay in sync.
|
||||
handoffs:
|
||||
- label: Build Specification
|
||||
agent: speckit.specify
|
||||
prompt: Implement the feature specification based on the updated constitution. I want to build...
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
@@ -135,4 +135,3 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
- Report final status with summary of completed work
|
||||
|
||||
Note: This command assumes a complete task breakdown exists in tasks.md. If tasks are incomplete or missing, suggest running `/speckit.tasks` first to regenerate the task list.
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
---
|
||||
description: Execute the implementation planning workflow using the plan template to generate design artifacts.
|
||||
handoffs:
|
||||
- label: Create Tasks
|
||||
agent: speckit.tasks
|
||||
prompt: Break the plan into tasks
|
||||
send: true
|
||||
- label: Create Checklist
|
||||
agent: speckit.checklist
|
||||
prompt: Create a checklist for the following domain...
|
||||
scripts:
|
||||
sh: scripts/bash/setup-plan.sh --json
|
||||
ps: scripts/powershell/setup-plan.ps1 -Json
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
---
|
||||
description: Create or update the feature specification from a natural language feature description.
|
||||
handoffs:
|
||||
- label: Build Technical Plan
|
||||
agent: speckit.plan
|
||||
prompt: Create a plan for the spec. I am building with...
|
||||
- label: Clarify Spec Requirements
|
||||
agent: speckit.clarify
|
||||
prompt: Clarify specification requirements
|
||||
send: true
|
||||
scripts:
|
||||
sh: scripts/bash/create-new-feature.sh --json "{ARGS}"
|
||||
ps: scripts/powershell/create-new-feature.ps1 -Json "{ARGS}"
|
||||
@@ -35,9 +43,9 @@ Given that feature description, do this:
|
||||
|
||||
**IMPORTANT**:
|
||||
|
||||
- Append the short-name argument to the `{SCRIPT}` command with the 2-4 word short name you created in step 1
|
||||
- Bash: `--short-name "your-generated-short-name"`
|
||||
- PowerShell: `-ShortName "your-generated-short-name"`
|
||||
- Append the short-name argument to the `{SCRIPT}` command with the 2-4 word short name you created in step 1. Keep the feature description as the final argument.
|
||||
- Bash example: `--short-name "your-generated-short-name" "Feature description here"`
|
||||
- PowerShell example: `-ShortName "your-generated-short-name" "Feature description here"`
|
||||
- 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")
|
||||
- You must only ever run this script once
|
||||
- The JSON is provided in the terminal as output - always refer to it to get the actual content you're looking for
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
---
|
||||
description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts.
|
||||
handoffs:
|
||||
- label: Analyze For Consistency
|
||||
agent: speckit.analyze
|
||||
prompt: Run a project analysis for consistency
|
||||
send: true
|
||||
- label: Implement Project
|
||||
agent: speckit.implement
|
||||
prompt: Start the implementation in phases
|
||||
send: true
|
||||
scripts:
|
||||
sh: scripts/bash/check-prerequisites.sh --json
|
||||
ps: scripts/powershell/check-prerequisites.ps1 -Json
|
||||
|
||||
31
templates/commands/taskstoissues.md
Normal file
31
templates/commands/taskstoissues.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
description: Generate an actionable, dependency-ordered tasks.md for the feature based on available design artifacts.
|
||||
tools: ['github/github-mcp-server/create_issue']
|
||||
scripts:
|
||||
sh: scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks
|
||||
ps: scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks
|
||||
---
|
||||
|
||||
## User Input
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## 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").
|
||||
1. From the executed script, extract the path to **tasks**.
|
||||
1. Get the Git remote by running:
|
||||
|
||||
```bash
|
||||
git config --get remote.origin.url
|
||||
```
|
||||
|
||||
**ONLY PROCEED TO NEXT STEPS IF THE REMOTE IS A GITHUB URL**
|
||||
|
||||
1. For each task in the list, use the GitHub MCP server to create a new issue in the repository that is representative of the Git remote.
|
||||
|
||||
**UNDER NO CIRCUMSTANCES EVER CREATE ISSUES IN REPOSITORIES THAT DO NOT MATCH THE REMOTE URL**
|
||||
Reference in New Issue
Block a user