diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index caf184c1c6..88acdcd5fd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -50,8 +50,6 @@ "kilocode.Kilo-Code", // Roo Code "RooVeterinaryInc.roo-cline", - // Amazon Developer Q - "AmazonWebServices.amazon-q-vscode", // Claude Code "anthropic.claude-code" ], diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index 9608a28a3d..ec3bd748ca 100755 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -51,32 +51,35 @@ echo -e "\nšŸ¤– Installing OpenCode CLI..." run_command "npm install -g opencode-ai@latest" echo "āœ… Done" -echo -e "\nšŸ¤– Installing Amazon Q CLI..." -# šŸ‘‰šŸ¾ https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-verify-download.html - -run_command "curl --proto '=https' --tlsv1.2 -sSf 'https://desktop-release.q.us-east-1.amazonaws.com/latest/q-x86_64-linux.zip' -o 'q.zip'" -run_command "curl --proto '=https' --tlsv1.2 -sSf 'https://desktop-release.q.us-east-1.amazonaws.com/latest/q-x86_64-linux.zip.sig' -o 'q.zip.sig'" -cat > amazonq-public-key.asc << 'EOF' ------BEGIN PGP PUBLIC KEY BLOCK----- - -mDMEZig60RYJKwYBBAHaRw8BAQdAy/+G05U5/EOA72WlcD4WkYn5SInri8pc4Z6D -BKNNGOm0JEFtYXpvbiBRIENMSSBUZWFtIDxxLWNsaUBhbWF6b24uY29tPoiZBBMW -CgBBFiEEmvYEF+gnQskUPgPsUNx6jcJMVmcFAmYoOtECGwMFCQPCZwAFCwkIBwIC -IgIGFQoJCAsCBBYCAwECHgcCF4AACgkQUNx6jcJMVmef5QD/QWWEGG/cOnbDnp68 -SJXuFkwiNwlH2rPw9ZRIQMnfAS0A/0V6ZsGB4kOylBfc7CNfzRFGtovdBBgHqA6P -zQ/PNscGuDgEZig60RIKKwYBBAGXVQEFAQEHQC4qleONMBCq3+wJwbZSr0vbuRba -D1xr4wUPn4Avn4AnAwEIB4h+BBgWCgAmFiEEmvYEF+gnQskUPgPsUNx6jcJMVmcF -AmYoOtECGwwFCQPCZwAACgkQUNx6jcJMVmchMgEA6l3RveCM0YHAGQaSFMkguoAo -vK6FgOkDawgP0NPIP2oA/jIAO4gsAntuQgMOsPunEdDeji2t+AhV02+DQIsXZpoB -=f8yY ------END PGP PUBLIC KEY BLOCK----- -EOF -run_command "gpg --batch --import amazonq-public-key.asc" -run_command "gpg --verify q.zip.sig q.zip" -run_command "unzip -q q.zip" -run_command "chmod +x ./q/install.sh" -run_command "./q/install.sh --no-confirm" -run_command "rm -rf ./q q.zip q.zip.sig amazonq-public-key.asc" +echo -e "\nšŸ¤– Installing Kiro CLI..." +# https://kiro.dev/docs/cli/ +KIRO_INSTALLER_URL="https://cli.kiro.dev/install" +KIRO_INSTALLER_PATH="$(mktemp)" + +cleanup_kiro_installer() { + rm -f "$KIRO_INSTALLER_PATH" +} +trap cleanup_kiro_installer EXIT + +run_command "curl -fsSL \"$KIRO_INSTALLER_URL\" -o \"$KIRO_INSTALLER_PATH\"" + +if [ -n "${KIRO_INSTALLER_SHA256:-}" ]; then + run_command "echo \"$KIRO_INSTALLER_SHA256 $KIRO_INSTALLER_PATH\" | sha256sum -c -" +fi + +run_command "bash \"$KIRO_INSTALLER_PATH\"" + +kiro_binary="" +if command -v kiro-cli >/dev/null 2>&1; then + kiro_binary="kiro-cli" +elif command -v kiro >/dev/null 2>&1; then + kiro_binary="kiro" +else + echo -e "\033[0;31m[ERROR] Kiro CLI installation did not create 'kiro-cli' or 'kiro' in PATH.\033[0m" >&2 + exit 1 +fi + +run_command "$kiro_binary --help > /dev/null" echo "āœ… Done" echo -e "\nšŸ¤– Installing CodeBuddy CLI..." diff --git a/.github/ISSUE_TEMPLATE/agent_request.yml b/.github/ISSUE_TEMPLATE/agent_request.yml index a72dacda52..a6ac6c4bff 100644 --- a/.github/ISSUE_TEMPLATE/agent_request.yml +++ b/.github/ISSUE_TEMPLATE/agent_request.yml @@ -8,7 +8,7 @@ body: value: | Thanks for requesting a new agent! Before submitting, please check if the agent is already supported. - **Currently supported agents**: Claude Code, Gemini CLI, GitHub Copilot, Cursor, Qwen Code, opencode, Codex CLI, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy, Qoder CLI, Amazon Q Developer CLI, Amp, SHAI, IBM Bob, Antigravity + **Currently supported agents**: Claude Code, Gemini CLI, GitHub Copilot, Cursor, Qwen Code, opencode, Codex CLI, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy, Qoder CLI, Kiro CLI, Amp, SHAI, IBM Bob, Antigravity - type: input id: agent-name diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index cbe1955ad4..dd09f8e02a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -75,7 +75,7 @@ body: - Roo Code - CodeBuddy - Qoder CLI - - Amazon Q Developer CLI + - Kiro CLI - Amp - SHAI - IBM Bob diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 71786ddcef..3b5889288b 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -69,7 +69,7 @@ body: - Roo Code - CodeBuddy - Qoder CLI - - Amazon Q Developer CLI + - Kiro CLI - Amp - SHAI - IBM Bob diff --git a/.github/workflows/scripts/create-github-release.sh b/.github/workflows/scripts/create-github-release.sh index 29f5024f8c..0418ce2b08 100644 --- a/.github/workflows/scripts/create-github-release.sh +++ b/.github/workflows/scripts/create-github-release.sh @@ -46,8 +46,8 @@ gh release create "$VERSION" \ .genreleases/spec-kit-template-amp-ps-"$VERSION".zip \ .genreleases/spec-kit-template-shai-sh-"$VERSION".zip \ .genreleases/spec-kit-template-shai-ps-"$VERSION".zip \ - .genreleases/spec-kit-template-q-sh-"$VERSION".zip \ - .genreleases/spec-kit-template-q-ps-"$VERSION".zip \ + .genreleases/spec-kit-template-kiro-cli-sh-"$VERSION".zip \ + .genreleases/spec-kit-template-kiro-cli-ps-"$VERSION".zip \ .genreleases/spec-kit-template-agy-sh-"$VERSION".zip \ .genreleases/spec-kit-template-agy-ps-"$VERSION".zip \ .genreleases/spec-kit-template-bob-sh-"$VERSION".zip \ diff --git a/.github/workflows/scripts/create-release-packages.ps1 b/.github/workflows/scripts/create-release-packages.ps1 index ed04d9cd3f..394500e556 100644 --- a/.github/workflows/scripts/create-release-packages.ps1 +++ b/.github/workflows/scripts/create-release-packages.ps1 @@ -14,7 +14,7 @@ .PARAMETER Agents Comma or space separated subset of agents to build (default: all) - Valid agents: claude, gemini, copilot, cursor-agent, qwen, opencode, windsurf, codex, kilocode, auggie, roo, codebuddy, amp, q, bob, qodercli, shai, agy, generic + Valid agents: claude, gemini, copilot, cursor-agent, qwen, opencode, windsurf, codex, kilocode, auggie, roo, codebuddy, amp, kiro-cli, bob, qodercli, shai, agy, generic .PARAMETER Scripts Comma or space separated subset of script types to build (default: both) @@ -335,9 +335,9 @@ function Build-Variant { $cmdDir = Join-Path $baseDir ".agents/commands" Generate-Commands -Agent 'amp' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script } - 'q' { - $cmdDir = Join-Path $baseDir ".amazonq/prompts" - Generate-Commands -Agent 'q' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script + 'kiro-cli' { + $cmdDir = Join-Path $baseDir ".kiro/prompts" + Generate-Commands -Agent 'kiro-cli' -Extension 'md' -ArgFormat '$ARGUMENTS' -OutputDir $cmdDir -ScriptVariant $Script } 'bob' { $cmdDir = Join-Path $baseDir ".bob/commands" @@ -360,7 +360,7 @@ function Build-Variant { } # Define all agents and scripts -$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'q', 'bob', 'qodercli', 'shai', 'agy', 'generic') +$AllAgents = @('claude', 'gemini', 'copilot', 'cursor-agent', 'qwen', 'opencode', 'windsurf', 'codex', 'kilocode', 'auggie', 'roo', 'codebuddy', 'amp', 'kiro-cli', 'bob', 'qodercli', 'shai', 'agy', 'generic') $AllScripts = @('sh', 'ps') function Normalize-List { @@ -425,4 +425,4 @@ foreach ($agent in $AgentList) { Write-Host "`nArchives in ${GenReleasesDir}:" Get-ChildItem -Path $GenReleasesDir -Filter "spec-kit-template-*-${Version}.zip" | ForEach-Object { Write-Host " $($_.Name)" -} \ No newline at end of file +} diff --git a/.github/workflows/scripts/create-release-packages.sh b/.github/workflows/scripts/create-release-packages.sh index 1b2ced3ea3..9a9d4589ca 100755 --- a/.github/workflows/scripts/create-release-packages.sh +++ b/.github/workflows/scripts/create-release-packages.sh @@ -6,7 +6,7 @@ set -euo pipefail # Usage: .github/workflows/scripts/create-release-packages.sh # Version argument should include leading 'v'. # Optionally set AGENTS and/or SCRIPTS env vars to limit what gets built. -# AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf codex amp shai bob generic (default: all) +# AGENTS : space or comma separated subset of: claude gemini copilot cursor-agent qwen opencode windsurf codex amp shai bob kiro-cli generic (default: all) # SCRIPTS : space or comma separated subset of: sh ps (default: both) # Examples: # AGENTS=claude SCRIPTS=sh $0 v0.2.0 @@ -212,9 +212,9 @@ build_variant() { shai) mkdir -p "$base_dir/.shai/commands" generate_commands shai md "\$ARGUMENTS" "$base_dir/.shai/commands" "$script" ;; - q) - mkdir -p "$base_dir/.amazonq/prompts" - generate_commands q md "\$ARGUMENTS" "$base_dir/.amazonq/prompts" "$script" ;; + kiro-cli) + mkdir -p "$base_dir/.kiro/prompts" + generate_commands kiro-cli md "\$ARGUMENTS" "$base_dir/.kiro/prompts" "$script" ;; agy) mkdir -p "$base_dir/.agent/workflows" generate_commands agy md "\$ARGUMENTS" "$base_dir/.agent/workflows" "$script" ;; @@ -230,7 +230,7 @@ build_variant() { } # Determine agent list -ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai q agy bob qodercli generic) +ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf codex kilocode auggie roo codebuddy amp shai kiro-cli agy bob qodercli generic) ALL_SCRIPTS=(sh ps) norm_list() { @@ -277,4 +277,3 @@ done echo "Archives in $GENRELEASES_DIR:" ls -1 "$GENRELEASES_DIR"/spec-kit-template-*-"${NEW_VERSION}".zip - diff --git a/AGENTS.md b/AGENTS.md index d8dc0f08f7..4cafa7defb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -44,7 +44,7 @@ Specify supports multiple AI agents by generating agent-specific command files a | **Roo Code** | `.roo/rules/` | Markdown | N/A (IDE-based) | Roo Code IDE | | **CodeBuddy CLI** | `.codebuddy/commands/` | Markdown | `codebuddy` | CodeBuddy CLI | | **Qoder CLI** | `.qoder/commands/` | Markdown | `qodercli` | Qoder CLI | -| **Amazon Q Developer CLI** | `.amazonq/prompts/` | Markdown | `q` | Amazon Q Developer CLI | +| **Kiro CLI** | `.kiro/prompts/` | Markdown | `kiro-cli` | Kiro CLI | | **Amp** | `.agents/commands/` | Markdown | `amp` | Amp CLI | | **SHAI** | `.shai/commands/` | Markdown | `shai` | SHAI CLI | | **IBM Bob** | `.bob/commands/` | Markdown | N/A (IDE-based) | IBM Bob IDE | @@ -86,7 +86,7 @@ This eliminates the need for special-case mappings throughout the codebase. - `folder`: Directory where agent-specific files are stored (relative to project root) - `commands_subdir`: Subdirectory name within the agent folder where command/prompt files are stored (default: `"commands"`) - Most agents use `"commands"` (e.g., `.claude/commands/`) - - Some agents use alternative names: `"agents"` (copilot), `"workflows"` (windsurf, kilocode, agy), `"prompts"` (codex, q), `"command"` (opencode - singular) + - Some agents use alternative names: `"agents"` (copilot), `"workflows"` (windsurf, kilocode, agy), `"prompts"` (codex, kiro-cli), `"command"` (opencode - singular) - This field enables `--ai-skills` to locate command templates correctly for skill generation - `install_url`: Installation documentation URL (set to `None` for IDE-based agents) - `requires_cli`: Whether the agent requires a CLI tool check during initialization @@ -96,7 +96,7 @@ This eliminates the need for special-case mappings throughout the codebase. Update the `--ai` parameter help text in the `init()` command to include the new agent: ```python -ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, new-agent-cli, or q"), +ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, new-agent-cli, or kiro-cli"), ``` Also update any function docstrings, examples, and error messages that list available agents. @@ -117,7 +117,7 @@ Modify `.github/workflows/scripts/create-release-packages.sh`: ##### Add to ALL_AGENTS array ```bash -ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf q) +ALL_AGENTS=(claude gemini copilot cursor-agent qwen opencode windsurf kiro-cli) ``` ##### Add case statement for directory structure @@ -317,7 +317,7 @@ Require a command-line tool to be installed: - **Cursor**: `cursor-agent` CLI - **Qwen Code**: `qwen` CLI - **opencode**: `opencode` CLI -- **Amazon Q Developer CLI**: `q` CLI +- **Kiro CLI**: `kiro-cli` CLI - **CodeBuddy CLI**: `codebuddy` CLI - **Qoder CLI**: `qodercli` CLI - **Amp**: `amp` CLI @@ -335,7 +335,7 @@ Work within integrated development environments: ### Markdown Format -Used by: Claude, Cursor, opencode, Windsurf, Amazon Q Developer, Amp, SHAI, IBM Bob +Used by: Claude, Cursor, opencode, Windsurf, Kiro CLI, Amp, SHAI, IBM Bob **Standard format:** diff --git a/CHANGELOG.md b/CHANGELOG.md index 741ce5d0cb..9ab2efe3c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ Recent 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.1.7] - 2026-02-25 + +### Changed + +- **Kiro CLI migration**: Replaced Amazon Q (`q`) integration with Kiro CLI (`kiro-cli`) across runtime config, release packaging, extension command registration, and documentation. + - Added canonical `kiro-cli` agent support with prompt directory `.kiro/prompts` + - Added `kiro` alias support for `specify init --ai` + - Updated context update scripts and release packaging scripts to emit Kiro artifacts + - Updated devcontainer setup to install Kiro CLI using the official installer command +- **Amazon Q retirement**: Removed Amazon Q (`q`) support from active agent configuration and release artifacts. + ## [0.1.6] - 2026-02-23 ### Fixed diff --git a/README.md b/README.md index 85a9a8f1e9..5316c3a2a4 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ Want to see Spec Kit in action? Watch our [video overview](https://www.youtube.c | Agent | Support | Notes | | ------------------------------------------------------------------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | [Qoder CLI](https://qoder.com/cli) | āœ… | | -| [Amazon Q Developer CLI](https://aws.amazon.com/developer/learning/q-developer-cli/) | āš ļø | Amazon Q Developer CLI [does not support](https://github.com/aws/amazon-q-developer-cli/issues/3064) custom arguments for slash commands. | +| [Kiro CLI](https://kiro.dev/docs/cli/) | āœ… | Use `--ai kiro-cli` (alias: `--ai kiro`) | | [Amp](https://ampcode.com/) | āœ… | | | [Auggie CLI](https://docs.augmentcode.com/cli/overview) | āœ… | | | [Claude Code](https://www.anthropic.com/claude-code) | āœ… | | @@ -173,14 +173,14 @@ The `specify` command supports the following options: | Command | Description | | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | `init` | Initialize a new Specify project from the latest template | -| `check` | Check for installed tools (`git`, `claude`, `gemini`, `code`/`code-insiders`, `cursor-agent`, `windsurf`, `qwen`, `opencode`, `codex`, `shai`, `qodercli`) | +| `check` | Check for installed tools (`git`, `claude`, `gemini`, `code`/`code-insiders`, `cursor-agent`, `windsurf`, `qwen`, `opencode`, `codex`, `kiro-cli`, `shai`, `qodercli`) | ### `specify init` Arguments & Options | Argument/Option | Type | Description | | ---------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `` | Argument | Name for your new project directory (optional if using `--here`, or use `.` for current directory) | -| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor-agent`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, `auggie`, `roo`, `codebuddy`, `amp`, `shai`, `q`, `agy`, `bob`, `qodercli`, or `generic` (requires `--ai-commands-dir`) | +| `--ai` | Option | AI assistant to use: `claude`, `gemini`, `copilot`, `cursor-agent`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, `auggie`, `roo`, `codebuddy`, `amp`, `shai`, `kiro-cli` (`kiro` alias), `agy`, `bob`, `qodercli`, or `generic` (requires `--ai-commands-dir`) | | `--ai-commands-dir` | Option | Directory for agent command files (required with `--ai generic`, e.g. `.myagent/commands/`) | | `--script` | Option | Script variant to use: `sh` (bash/zsh) or `ps` (PowerShell) | | `--ignore-agent-tools` | Flag | Skip checks for AI agent tools like Claude Code | @@ -210,6 +210,9 @@ specify init my-project --ai qodercli # Initialize with Windsurf support specify init my-project --ai windsurf +# Initialize with Kiro CLI support +specify init my-project --ai kiro-cli + # Initialize with Amp support specify init my-project --ai amp @@ -393,7 +396,7 @@ specify init . --force --ai claude specify init --here --force --ai claude ``` -The CLI will check if you have Claude Code, Gemini CLI, Cursor CLI, Qwen CLI, opencode, Codex CLI, Qoder CLI, or Amazon Q Developer CLI installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command: +The CLI will check if you have Claude Code, Gemini CLI, Cursor CLI, Qwen CLI, opencode, Codex CLI, Qoder CLI, or Kiro CLI installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command: ```bash specify init --ai claude --ignore-agent-tools diff --git a/pyproject.toml b/pyproject.toml index 5f6a2eb7ab..b8a701b9aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "specify-cli" -version = "0.1.6" +version = "0.1.7" description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)." requires-python = ">=3.11" dependencies = [ @@ -51,4 +51,3 @@ precision = 2 show_missing = true skip_covered = false - diff --git a/scripts/bash/update-agent-context.sh b/scripts/bash/update-agent-context.sh index a33ea5cdee..c7c118507e 100644 --- a/scripts/bash/update-agent-context.sh +++ b/scripts/bash/update-agent-context.sh @@ -30,12 +30,12 @@ # # 5. Multi-Agent Support # - Handles agent-specific file paths and naming conventions -# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Qoder CLI, Amp, SHAI, Amazon Q Developer CLI, or Antigravity +# - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Qoder CLI, Amp, SHAI, Kiro CLI, or Antigravity # - Can update single agents or all existing agent files # - Creates default Claude file if no agent files exist # # Usage: ./update-agent-context.sh [agent_type] -# Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qodercli +# Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli # Leave empty to update all existing agent files set -e @@ -73,7 +73,7 @@ CODEBUDDY_FILE="$REPO_ROOT/CODEBUDDY.md" QODER_FILE="$REPO_ROOT/QODER.md" AMP_FILE="$REPO_ROOT/AGENTS.md" SHAI_FILE="$REPO_ROOT/SHAI.md" -Q_FILE="$REPO_ROOT/AGENTS.md" +KIRO_FILE="$REPO_ROOT/AGENTS.md" AGY_FILE="$REPO_ROOT/.agent/rules/specify-rules.md" BOB_FILE="$REPO_ROOT/AGENTS.md" @@ -628,8 +628,8 @@ update_specific_agent() { shai) update_agent_file "$SHAI_FILE" "SHAI" ;; - q) - update_agent_file "$Q_FILE" "Amazon Q Developer CLI" + kiro-cli) + update_agent_file "$KIRO_FILE" "Kiro CLI" ;; agy) update_agent_file "$AGY_FILE" "Antigravity" @@ -642,7 +642,7 @@ update_specific_agent() { ;; *) log_error "Unknown agent type '$agent_type'" - log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qodercli|generic" + log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli|generic" exit 1 ;; esac @@ -717,8 +717,8 @@ update_all_existing_agents() { found_agent=true fi - if [[ -f "$Q_FILE" ]]; then - update_agent_file "$Q_FILE" "Amazon Q Developer CLI" + if [[ -f "$KIRO_FILE" ]]; then + update_agent_file "$KIRO_FILE" "Kiro CLI" found_agent=true fi @@ -755,7 +755,7 @@ print_summary() { echo - log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qodercli]" + log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli]" } #============================================================================== @@ -807,4 +807,3 @@ main() { if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi - diff --git a/scripts/powershell/update-agent-context.ps1 b/scripts/powershell/update-agent-context.ps1 index 61718e96ce..6ca9430f11 100644 --- a/scripts/powershell/update-agent-context.ps1 +++ b/scripts/powershell/update-agent-context.ps1 @@ -9,7 +9,7 @@ Mirrors the behavior of scripts/bash/update-agent-context.sh: 2. Plan Data Extraction 3. Agent File Management (create from template or update existing) 4. Content Generation (technology stack, recent changes, timestamp) - 5. Multi-Agent Support (claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, roo, codebuddy, amp, shai, q, agy, bob, qodercli) + 5. Multi-Agent Support (claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, roo, codebuddy, amp, shai, kiro-cli, agy, bob, qodercli) .PARAMETER AgentType Optional agent key to update a single agent. If omitted, updates all existing agent files (creating a default Claude file if none exist). @@ -25,7 +25,7 @@ Relies on common helper functions in common.ps1 #> param( [Parameter(Position=0)] - [ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','q','agy','bob','qodercli','generic')] + [ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','kiro-cli','agy','bob','qodercli','generic')] [string]$AgentType ) @@ -58,7 +58,7 @@ $CODEBUDDY_FILE = Join-Path $REPO_ROOT 'CODEBUDDY.md' $QODER_FILE = Join-Path $REPO_ROOT 'QODER.md' $AMP_FILE = Join-Path $REPO_ROOT 'AGENTS.md' $SHAI_FILE = Join-Path $REPO_ROOT 'SHAI.md' -$Q_FILE = Join-Path $REPO_ROOT 'AGENTS.md' +$KIRO_FILE = Join-Path $REPO_ROOT 'AGENTS.md' $AGY_FILE = Join-Path $REPO_ROOT '.agent/rules/specify-rules.md' $BOB_FILE = Join-Path $REPO_ROOT 'AGENTS.md' @@ -387,11 +387,11 @@ function Update-SpecificAgent { 'qodercli' { Update-AgentFile -TargetFile $QODER_FILE -AgentName 'Qoder CLI' } 'amp' { Update-AgentFile -TargetFile $AMP_FILE -AgentName 'Amp' } 'shai' { Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI' } - 'q' { Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI' } + 'kiro-cli' { Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro CLI' } 'agy' { Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity' } 'bob' { Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob' } 'generic' { Write-Info 'Generic agent: no predefined context file. Use the agent-specific update script for your agent.' } - default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qodercli|generic'; return $false } + default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli|generic'; return $false } } } @@ -411,7 +411,7 @@ function Update-AllExistingAgents { if (Test-Path $CODEBUDDY_FILE) { if (-not (Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI')) { $ok = $false }; $found = $true } if (Test-Path $QODER_FILE) { if (-not (Update-AgentFile -TargetFile $QODER_FILE -AgentName 'Qoder CLI')) { $ok = $false }; $found = $true } if (Test-Path $SHAI_FILE) { if (-not (Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI')) { $ok = $false }; $found = $true } - if (Test-Path $Q_FILE) { if (-not (Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI')) { $ok = $false }; $found = $true } + if (Test-Path $KIRO_FILE) { if (-not (Update-AgentFile -TargetFile $KIRO_FILE -AgentName 'Kiro CLI')) { $ok = $false }; $found = $true } if (Test-Path $AGY_FILE) { if (-not (Update-AgentFile -TargetFile $AGY_FILE -AgentName 'Antigravity')) { $ok = $false }; $found = $true } if (Test-Path $BOB_FILE) { if (-not (Update-AgentFile -TargetFile $BOB_FILE -AgentName 'IBM Bob')) { $ok = $false }; $found = $true } if (-not $found) { @@ -428,7 +428,7 @@ function Print-Summary { if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" } if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" } Write-Host '' - Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q|agy|bob|qodercli|generic]' + Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|kiro-cli|agy|bob|qodercli|generic]' } function Main { @@ -449,4 +449,3 @@ function Main { } Main - diff --git a/src/specify_cli/__init__.py b/src/specify_cli/__init__.py index 5651ac7226..29b035826c 100644 --- a/src/specify_cli/__init__.py +++ b/src/specify_cli/__init__.py @@ -216,11 +216,11 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str) "install_url": None, # IDE-based "requires_cli": False, }, - "q": { - "name": "Amazon Q Developer CLI", - "folder": ".amazonq/", + "kiro-cli": { + "name": "Kiro CLI", + "folder": ".kiro/", "commands_subdir": "prompts", # Special: uses prompts/ not commands/ - "install_url": "https://aws.amazon.com/developer/learning/q-developer-cli/", + "install_url": "https://kiro.dev/docs/cli/", "requires_cli": True, }, "amp": { @@ -260,6 +260,10 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str) }, } +AI_ASSISTANT_ALIASES = { + "kiro": "kiro-cli", +} + SCRIPT_TYPE_CHOICES = {"sh": "POSIX Shell (bash/zsh)", "ps": "PowerShell"} CLAUDE_LOCAL_PATH = Path.home() / ".claude" / "local" / "claude" @@ -534,7 +538,12 @@ def check_tool(tool: str, tracker: StepTracker = None) -> bool: tracker.complete(tool, "available") return True - found = shutil.which(tool) is not None + if tool == "kiro-cli": + # Kiro currently supports both executable names. Prefer kiro-cli and + # accept kiro as a compatibility fallback. + found = shutil.which("kiro-cli") is not None or shutil.which("kiro") is not None + else: + found = shutil.which(tool) is not None if tracker: if found: @@ -1214,7 +1223,7 @@ def install_ai_skills(project_path: Path, selected_ai: str, tracker: StepTracker @app.command() def init( project_name: str = typer.Argument(None, help="Name for your new project directory (optional if using --here, or use '.' for current directory)"), - ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, amp, shai, q, agy, bob, qodercli, or generic (requires --ai-commands-dir)"), + ai_assistant: str = typer.Option(None, "--ai", help="AI assistant to use: claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, codebuddy, amp, shai, kiro-cli (alias: kiro), agy, bob, qodercli, or generic (requires --ai-commands-dir)"), ai_commands_dir: str = typer.Option(None, "--ai-commands-dir", help="Directory for agent command files (required with --ai generic, e.g. .myagent/commands/)"), script_type: str = typer.Option(None, "--script", help="Script type to use: sh or ps"), ignore_agent_tools: bool = typer.Option(False, "--ignore-agent-tools", help="Skip checks for AI agent tools like Claude Code"), @@ -1270,6 +1279,9 @@ def init( console.print("[yellow]Example:[/yellow] specify init --ai generic --ai-commands-dir .myagent/commands/") raise typer.Exit(1) + if ai_assistant: + ai_assistant = AI_ASSISTANT_ALIASES.get(ai_assistant, ai_assistant) + if project_name == ".": here = True project_name = None # Clear project_name to use existing validation logic @@ -2350,4 +2362,3 @@ def main(): if __name__ == "__main__": main() - diff --git a/src/specify_cli/extensions.py b/src/specify_cli/extensions.py index b8881e7c89..5a90b4d58d 100644 --- a/src/specify_cli/extensions.py +++ b/src/specify_cli/extensions.py @@ -653,8 +653,8 @@ class CommandRegistrar: "args": "$ARGUMENTS", "extension": ".md" }, - "q": { - "dir": ".amazonq/prompts", + "kiro-cli": { + "dir": ".kiro/prompts", "format": "markdown", "args": "$ARGUMENTS", "extension": ".md" @@ -1782,4 +1782,3 @@ def disable_hooks(self, extension_id: str): self.save_project_config(config) - diff --git a/tests/test_agent_config_consistency.py b/tests/test_agent_config_consistency.py new file mode 100644 index 0000000000..7c81883d57 --- /dev/null +++ b/tests/test_agent_config_consistency.py @@ -0,0 +1,73 @@ +"""Consistency checks for agent configuration across runtime and packaging scripts.""" + +import re +from pathlib import Path + +from specify_cli import AGENT_CONFIG +from specify_cli.extensions import CommandRegistrar + + +REPO_ROOT = Path(__file__).resolve().parent.parent + + +class TestAgentConfigConsistency: + """Ensure kiro-cli migration stays synchronized across key surfaces.""" + + def test_runtime_config_uses_kiro_cli_and_removes_q(self): + """AGENT_CONFIG should include kiro-cli and exclude legacy q.""" + assert "kiro-cli" in AGENT_CONFIG + assert AGENT_CONFIG["kiro-cli"]["folder"] == ".kiro/" + assert AGENT_CONFIG["kiro-cli"]["commands_subdir"] == "prompts" + assert "q" not in AGENT_CONFIG + + def test_extension_registrar_uses_kiro_cli_and_removes_q(self): + """Extension command registrar should target .kiro/prompts.""" + cfg = CommandRegistrar.AGENT_CONFIGS + + assert "kiro-cli" in cfg + assert cfg["kiro-cli"]["dir"] == ".kiro/prompts" + assert "q" not in cfg + + def test_release_agent_lists_include_kiro_cli_and_exclude_q(self): + """Bash and PowerShell release scripts should agree on agent key set for Kiro.""" + sh_text = (REPO_ROOT / ".github" / "workflows" / "scripts" / "create-release-packages.sh").read_text(encoding="utf-8") + ps_text = (REPO_ROOT / ".github" / "workflows" / "scripts" / "create-release-packages.ps1").read_text(encoding="utf-8") + + sh_match = re.search(r"ALL_AGENTS=\(([^)]*)\)", sh_text) + assert sh_match is not None + sh_agents = sh_match.group(1).split() + + ps_match = re.search(r"\$AllAgents = @\(([^)]*)\)", ps_text) + assert ps_match is not None + ps_agents = re.findall(r"'([^']+)'", ps_match.group(1)) + + assert "kiro-cli" in sh_agents + assert "kiro-cli" in ps_agents + assert "q" not in sh_agents + assert "q" not in ps_agents + + def test_release_output_targets_kiro_prompt_dir(self): + """Packaging and release scripts should no longer emit amazonq artifacts.""" + sh_text = (REPO_ROOT / ".github" / "workflows" / "scripts" / "create-release-packages.sh").read_text(encoding="utf-8") + ps_text = (REPO_ROOT / ".github" / "workflows" / "scripts" / "create-release-packages.ps1").read_text(encoding="utf-8") + gh_release_text = (REPO_ROOT / ".github" / "workflows" / "scripts" / "create-github-release.sh").read_text(encoding="utf-8") + + assert ".kiro/prompts" in sh_text + assert ".kiro/prompts" in ps_text + assert ".amazonq/prompts" not in sh_text + assert ".amazonq/prompts" not in ps_text + + assert "spec-kit-template-kiro-cli-sh-" in gh_release_text + assert "spec-kit-template-kiro-cli-ps-" in gh_release_text + assert "spec-kit-template-q-sh-" not in gh_release_text + assert "spec-kit-template-q-ps-" not in gh_release_text + + def test_agent_context_scripts_use_kiro_cli(self): + """Agent context scripts should advertise kiro-cli and not legacy q agent key.""" + bash_text = (REPO_ROOT / "scripts" / "bash" / "update-agent-context.sh").read_text(encoding="utf-8") + pwsh_text = (REPO_ROOT / "scripts" / "powershell" / "update-agent-context.ps1").read_text(encoding="utf-8") + + assert "kiro-cli" in bash_text + assert "kiro-cli" in pwsh_text + assert "Amazon Q Developer CLI" not in bash_text + assert "Amazon Q Developer CLI" not in pwsh_text diff --git a/tests/test_ai_skills.py b/tests/test_ai_skills.py index 3eec4a419c..2533001012 100644 --- a/tests/test_ai_skills.py +++ b/tests/test_ai_skills.py @@ -162,6 +162,11 @@ def test_cursor_agent_skills_dir(self, project_dir): result = _get_skills_dir(project_dir, "cursor-agent") assert result == project_dir / ".cursor" / "skills" + def test_kiro_cli_skills_dir(self, project_dir): + """Kiro CLI should use .kiro/skills/.""" + result = _get_skills_dir(project_dir, "kiro-cli") + assert result == project_dir / ".kiro" / "skills" + def test_unknown_agent_uses_default(self, project_dir): """Unknown agents should fall back to DEFAULT_SKILLS_DIR.""" result = _get_skills_dir(project_dir, "nonexistent-agent") @@ -483,6 +488,7 @@ def fake_download(project_path, *args, **kwargs): patch("specify_cli.shutil.which", return_value="/usr/bin/git"): result = runner.invoke(app, ["init", str(target), "--ai", "claude", "--ai-skills", "--script", "sh", "--no-git"]) + assert result.exit_code == 0 # Skills should have been called mock_skills.assert_called_once() @@ -508,6 +514,7 @@ def fake_download(project_path, *args, **kwargs): patch("specify_cli.shutil.which", return_value="/usr/bin/git"): result = runner.invoke(app, ["init", str(target), "--ai", "claude", "--ai-skills", "--script", "sh", "--no-git"]) + assert result.exit_code == 0 # Commands should still exist since skills failed cmds_dir = target / ".claude" / "commands" assert cmds_dir.exists() @@ -538,8 +545,9 @@ def fake_download(project_path, *args, **kwargs): patch("specify_cli.install_ai_skills", return_value=True), \ patch("specify_cli.is_git_repo", return_value=True), \ patch("specify_cli.shutil.which", return_value="/usr/bin/git"): - result = runner.invoke(app, ["init", "--here", "--ai", "claude", "--ai-skills", "--script", "sh", "--no-git"]) + result = runner.invoke(app, ["init", "--here", "--ai", "claude", "--ai-skills", "--script", "sh", "--no-git"], input="y\n") + assert result.exit_code == 0 # Commands must remain for --here assert cmds_dir.exists() assert (cmds_dir / "speckit.specify.md").exists() @@ -631,6 +639,42 @@ def test_ai_skills_flag_appears_in_help(self): assert "--ai-skills" in plain assert "agent skills" in plain.lower() + def test_kiro_alias_normalized_to_kiro_cli(self, tmp_path): + """--ai kiro should normalize to canonical kiro-cli agent key.""" + from typer.testing import CliRunner + + runner = CliRunner() + target = tmp_path / "kiro-alias-proj" + + with patch("specify_cli.download_and_extract_template") as mock_download, \ + patch("specify_cli.ensure_executable_scripts"), \ + patch("specify_cli.ensure_constitution_from_template"), \ + patch("specify_cli.is_git_repo", return_value=False), \ + patch("specify_cli.shutil.which", return_value="/usr/bin/git"): + result = runner.invoke( + app, + [ + "init", + str(target), + "--ai", + "kiro", + "--ignore-agent-tools", + "--script", + "sh", + "--no-git", + ], + ) + + assert result.exit_code == 0 + assert mock_download.called + # download_and_extract_template(project_path, ai_assistant, script_type, ...) + assert mock_download.call_args.args[1] == "kiro-cli" + + def test_q_removed_from_agent_config(self): + """Amazon Q legacy key should not remain in AGENT_CONFIG.""" + assert "q" not in AGENT_CONFIG + assert "kiro-cli" in AGENT_CONFIG + class TestParameterOrderingIssue: """Test fix for GitHub issue #1641: parameter ordering issues.""" diff --git a/tests/test_extensions.py b/tests/test_extensions.py index a2c4121ed4..e6849729e3 100644 --- a/tests/test_extensions.py +++ b/tests/test_extensions.py @@ -399,6 +399,12 @@ def test_config_backup_on_remove(self, extension_dir, project_dir): class TestCommandRegistrar: """Test CommandRegistrar command registration.""" + def test_kiro_cli_agent_config_present(self): + """Kiro CLI should be mapped to .kiro/prompts and legacy q removed.""" + assert "kiro-cli" in CommandRegistrar.AGENT_CONFIGS + assert CommandRegistrar.AGENT_CONFIGS["kiro-cli"]["dir"] == ".kiro/prompts" + assert "q" not in CommandRegistrar.AGENT_CONFIGS + def test_parse_frontmatter_valid(self): """Test parsing valid YAML frontmatter.""" content = """---