mirror of
https://github.com/github/spec-kit.git
synced 2026-03-22 13:23:08 +00:00
Compare commits
6 Commits
68d1d3a0fc
...
v0.1.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f444ccba3a | ||
|
|
3040d33c31 | ||
|
|
6cc61025cb | ||
|
|
c1034f1d9d | ||
|
|
cee4f26fac | ||
|
|
6f523ede22 |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1,3 +1,3 @@
|
|||||||
# Global code owner
|
# Global code owner
|
||||||
* @localden
|
* @mnriem
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ AGENT_CONFIG = {
|
|||||||
"new-agent-cli": { # Use the ACTUAL CLI tool name (what users type in terminal)
|
"new-agent-cli": { # Use the ACTUAL CLI tool name (what users type in terminal)
|
||||||
"name": "New Agent Display Name",
|
"name": "New Agent Display Name",
|
||||||
"folder": ".newagent/", # Directory for agent files
|
"folder": ".newagent/", # Directory for agent files
|
||||||
|
"commands_subdir": "commands", # Subdirectory name for command files (default: "commands")
|
||||||
"install_url": "https://example.com/install", # URL for installation docs (or None if IDE-based)
|
"install_url": "https://example.com/install", # URL for installation docs (or None if IDE-based)
|
||||||
"requires_cli": True, # True if CLI tool required, False for IDE-based agents
|
"requires_cli": True, # True if CLI tool required, False for IDE-based agents
|
||||||
},
|
},
|
||||||
@@ -83,6 +84,10 @@ This eliminates the need for special-case mappings throughout the codebase.
|
|||||||
|
|
||||||
- `name`: Human-readable display name shown to users
|
- `name`: Human-readable display name shown to users
|
||||||
- `folder`: Directory where agent-specific files are stored (relative to project root)
|
- `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)
|
||||||
|
- 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)
|
- `install_url`: Installation documentation URL (set to `None` for IDE-based agents)
|
||||||
- `requires_cli`: Whether the agent requires a CLI tool check during initialization
|
- `requires_cli`: Whether the agent requires a CLI tool check during initialization
|
||||||
|
|
||||||
|
|||||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -2,18 +2,38 @@
|
|||||||
|
|
||||||
<!-- markdownlint-disable MD024 -->
|
<!-- markdownlint-disable MD024 -->
|
||||||
|
|
||||||
All notable changes to the Specify CLI and templates are documented here.
|
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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [0.1.4] - Unreleased
|
## [0.1.6] - 2026-02-23
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Parameter Ordering Issues (#1641)**: Fixed CLI parameter parsing issue where option flags were incorrectly consumed as values for preceding options
|
||||||
|
- Added validation to detect when `--ai` or `--ai-commands-dir` incorrectly consume following flags like `--here` or `--ai-skills`
|
||||||
|
- Now provides clear error messages: "Invalid value for --ai: '--here'"
|
||||||
|
- Includes helpful hints suggesting proper usage and listing available agents
|
||||||
|
- Commands like `specify init --ai-skills --ai --here` now fail with actionable feedback instead of confusing "Must specify project name" errors
|
||||||
|
- Added comprehensive test suite (5 new tests) to prevent regressions
|
||||||
|
|
||||||
|
## [0.1.5] - 2026-02-21
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **AI Skills Installation Bug (#1658)**: Fixed `--ai-skills` flag not generating skill files for GitHub Copilot and other agents with non-standard command directory structures
|
||||||
|
- Added `commands_subdir` field to `AGENT_CONFIG` to explicitly specify the subdirectory name for each agent
|
||||||
|
- Affected agents now work correctly: copilot (`.github/agents/`), opencode (`.opencode/command/`), windsurf (`.windsurf/workflows/`), codex (`.codex/prompts/`), kilocode (`.kilocode/workflows/`), q (`.amazonq/prompts/`), and agy (`.agent/workflows/`)
|
||||||
|
- The `install_ai_skills()` function now uses the correct path for all agents instead of assuming `commands/` for everyone
|
||||||
|
|
||||||
|
## [0.1.4] - 2026-02-20
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- **Qoder CLI detection**: Renamed `AGENT_CONFIG` key from `"qoder"` to `"qodercli"` to match the actual executable name, fixing `specify check` and `specify init --ai` detection failures
|
- **Qoder CLI detection**: Renamed `AGENT_CONFIG` key from `"qoder"` to `"qodercli"` to match the actual executable name, fixing `specify check` and `specify init --ai` detection failures
|
||||||
|
|
||||||
## [0.1.3] - Unreleased
|
## [0.1.3] - 2026-02-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
@@ -60,7 +80,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
## [0.0.94] - 2026-02-11
|
## [0.0.94] - 2026-02-11
|
||||||
|
|
||||||
- Add stale workflow for 180-day inactive issues and PRs (#1594)
|
- Add stale workflow for 180-day inactive issues and PRs (#1594)
|
||||||
|
|
||||||
## [0.0.93] - 2026-02-10
|
|
||||||
|
|
||||||
- Add modular extension system (#1551)
|
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ Then, use the `/speckit.implement` slash command to execute the plan.
|
|||||||
/speckit.implement
|
/speckit.implement
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> **Phased Implementation**: For complex projects, implement in phases to avoid overwhelming the agent's context. Start with core functionality, validate it works, then add features incrementally.
|
||||||
|
|
||||||
## Detailed Example: Building Taskify
|
## Detailed Example: Building Taskify
|
||||||
|
|
||||||
Here's a complete example of building a team productivity platform:
|
Here's a complete example of building a team productivity platform:
|
||||||
@@ -135,7 +138,15 @@ Be specific about your tech stack and technical requirements:
|
|||||||
/speckit.plan We are going to generate this using .NET Aspire, using Postgres as the database. The frontend should use Blazor server with drag-and-drop task boards, real-time updates. There should be a REST API created with a projects API, tasks API, and a notifications API.
|
/speckit.plan We are going to generate this using .NET Aspire, using Postgres as the database. The frontend should use Blazor server with drag-and-drop task boards, real-time updates. There should be a REST API created with a projects API, tasks API, and a notifications API.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 6: Validate and Implement
|
### Step 6: Define Tasks
|
||||||
|
|
||||||
|
Generate an actionable task list using the `/speckit.tasks` command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/speckit.tasks
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: Validate and Implement
|
||||||
|
|
||||||
Have your AI agent audit the implementation plan using `/speckit.analyze`:
|
Have your AI agent audit the implementation plan using `/speckit.analyze`:
|
||||||
|
|
||||||
@@ -149,6 +160,9 @@ Finally, implement the solution:
|
|||||||
/speckit.implement
|
/speckit.implement
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> **Phased Implementation**: For large projects like Taskify, consider implementing in phases (e.g., Phase 1: Basic project/task structure, Phase 2: Kanban functionality, Phase 3: Comments and assignments). This prevents context saturation and allows for validation at each stage.
|
||||||
|
|
||||||
## Key Principles
|
## Key Principles
|
||||||
|
|
||||||
- **Be explicit** about what you're building and why
|
- **Be explicit** about what you're building and why
|
||||||
|
|||||||
@@ -1,15 +1,41 @@
|
|||||||
{
|
{
|
||||||
"schema_version": "1.0",
|
"schema_version": "1.0",
|
||||||
"updated_at": "2026-02-20T00:00:00Z",
|
"updated_at": "2026-02-22T00:00:00Z",
|
||||||
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json",
|
"catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/extensions/catalog.community.json",
|
||||||
"extensions": {
|
"extensions": {
|
||||||
|
"cleanup": {
|
||||||
|
"name": "Cleanup Extension",
|
||||||
|
"id": "cleanup",
|
||||||
|
"description": "Post-implementation quality gate that reviews changes, fixes small issues (scout rule), creates tasks for medium issues, and generates analysis for large issues.",
|
||||||
|
"author": "dsrednicki",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"download_url": "https://github.com/dsrednicki/spec-kit-cleanup/archive/refs/tags/v1.0.0.zip",
|
||||||
|
"repository": "https://github.com/dsrednicki/spec-kit-cleanup",
|
||||||
|
"homepage": "https://github.com/dsrednicki/spec-kit-cleanup",
|
||||||
|
"documentation": "https://github.com/dsrednicki/spec-kit-cleanup/blob/main/README.md",
|
||||||
|
"changelog": "https://github.com/dsrednicki/spec-kit-cleanup/blob/main/CHANGELOG.md",
|
||||||
|
"license": "MIT",
|
||||||
|
"requires": {
|
||||||
|
"speckit_version": ">=0.1.0"
|
||||||
|
},
|
||||||
|
"provides": {
|
||||||
|
"commands": 1,
|
||||||
|
"hooks": 1
|
||||||
|
},
|
||||||
|
"tags": ["quality", "tech-debt", "review", "cleanup", "scout-rule"],
|
||||||
|
"verified": false,
|
||||||
|
"downloads": 0,
|
||||||
|
"stars": 0,
|
||||||
|
"created_at": "2026-02-22T00:00:00Z",
|
||||||
|
"updated_at": "2026-02-22T00:00:00Z"
|
||||||
|
},
|
||||||
"v-model": {
|
"v-model": {
|
||||||
"name": "V-Model Extension Pack",
|
"name": "V-Model Extension Pack",
|
||||||
"id": "v-model",
|
"id": "v-model",
|
||||||
"description": "Enforces V-Model paired generation of development specs and test specs with full traceability.",
|
"description": "Enforces V-Model paired generation of development specs and test specs with full traceability.",
|
||||||
"author": "leocamello",
|
"author": "leocamello",
|
||||||
"version": "0.2.0",
|
"version": "0.4.0",
|
||||||
"download_url": "https://github.com/leocamello/spec-kit-v-model/archive/refs/tags/v0.2.0.zip",
|
"download_url": "https://github.com/leocamello/spec-kit-v-model/archive/refs/tags/v0.4.0.zip",
|
||||||
"repository": "https://github.com/leocamello/spec-kit-v-model",
|
"repository": "https://github.com/leocamello/spec-kit-v-model",
|
||||||
"homepage": "https://github.com/leocamello/spec-kit-v-model",
|
"homepage": "https://github.com/leocamello/spec-kit-v-model",
|
||||||
"documentation": "https://github.com/leocamello/spec-kit-v-model/blob/main/README.md",
|
"documentation": "https://github.com/leocamello/spec-kit-v-model/blob/main/README.md",
|
||||||
@@ -19,7 +45,7 @@
|
|||||||
"speckit_version": ">=0.1.0"
|
"speckit_version": ">=0.1.0"
|
||||||
},
|
},
|
||||||
"provides": {
|
"provides": {
|
||||||
"commands": 5,
|
"commands": 9,
|
||||||
"hooks": 1
|
"hooks": 1
|
||||||
},
|
},
|
||||||
"tags": ["v-model", "traceability", "testing", "compliance", "safety-critical"],
|
"tags": ["v-model", "traceability", "testing", "compliance", "safety-critical"],
|
||||||
@@ -27,7 +53,7 @@
|
|||||||
"downloads": 0,
|
"downloads": 0,
|
||||||
"stars": 0,
|
"stars": 0,
|
||||||
"created_at": "2026-02-20T00:00:00Z",
|
"created_at": "2026-02-20T00:00:00Z",
|
||||||
"updated_at": "2026-02-20T00:00:00Z"
|
"updated_at": "2026-02-22T00:00:00Z"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "specify-cli"
|
name = "specify-cli"
|
||||||
version = "0.1.4"
|
version = "0.1.6"
|
||||||
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
|
description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|||||||
@@ -123,119 +123,138 @@ def _format_rate_limit_error(status_code: int, headers: httpx.Headers, url: str)
|
|||||||
|
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
# Agent configuration with name, folder, install URL, and CLI tool requirement
|
# Agent configuration with name, folder, install URL, CLI tool requirement, and commands subdirectory
|
||||||
AGENT_CONFIG = {
|
AGENT_CONFIG = {
|
||||||
"copilot": {
|
"copilot": {
|
||||||
"name": "GitHub Copilot",
|
"name": "GitHub Copilot",
|
||||||
"folder": ".github/",
|
"folder": ".github/",
|
||||||
|
"commands_subdir": "agents", # Special: uses agents/ not commands/
|
||||||
"install_url": None, # IDE-based, no CLI check needed
|
"install_url": None, # IDE-based, no CLI check needed
|
||||||
"requires_cli": False,
|
"requires_cli": False,
|
||||||
},
|
},
|
||||||
"claude": {
|
"claude": {
|
||||||
"name": "Claude Code",
|
"name": "Claude Code",
|
||||||
"folder": ".claude/",
|
"folder": ".claude/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": "https://docs.anthropic.com/en/docs/claude-code/setup",
|
"install_url": "https://docs.anthropic.com/en/docs/claude-code/setup",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"gemini": {
|
"gemini": {
|
||||||
"name": "Gemini CLI",
|
"name": "Gemini CLI",
|
||||||
"folder": ".gemini/",
|
"folder": ".gemini/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": "https://github.com/google-gemini/gemini-cli",
|
"install_url": "https://github.com/google-gemini/gemini-cli",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"cursor-agent": {
|
"cursor-agent": {
|
||||||
"name": "Cursor",
|
"name": "Cursor",
|
||||||
"folder": ".cursor/",
|
"folder": ".cursor/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": None, # IDE-based
|
"install_url": None, # IDE-based
|
||||||
"requires_cli": False,
|
"requires_cli": False,
|
||||||
},
|
},
|
||||||
"qwen": {
|
"qwen": {
|
||||||
"name": "Qwen Code",
|
"name": "Qwen Code",
|
||||||
"folder": ".qwen/",
|
"folder": ".qwen/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": "https://github.com/QwenLM/qwen-code",
|
"install_url": "https://github.com/QwenLM/qwen-code",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"opencode": {
|
"opencode": {
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"folder": ".opencode/",
|
"folder": ".opencode/",
|
||||||
|
"commands_subdir": "command", # Special: singular 'command' not 'commands'
|
||||||
"install_url": "https://opencode.ai",
|
"install_url": "https://opencode.ai",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"codex": {
|
"codex": {
|
||||||
"name": "Codex CLI",
|
"name": "Codex CLI",
|
||||||
"folder": ".codex/",
|
"folder": ".codex/",
|
||||||
|
"commands_subdir": "prompts", # Special: uses prompts/ not commands/
|
||||||
"install_url": "https://github.com/openai/codex",
|
"install_url": "https://github.com/openai/codex",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"windsurf": {
|
"windsurf": {
|
||||||
"name": "Windsurf",
|
"name": "Windsurf",
|
||||||
"folder": ".windsurf/",
|
"folder": ".windsurf/",
|
||||||
|
"commands_subdir": "workflows", # Special: uses workflows/ not commands/
|
||||||
"install_url": None, # IDE-based
|
"install_url": None, # IDE-based
|
||||||
"requires_cli": False,
|
"requires_cli": False,
|
||||||
},
|
},
|
||||||
"kilocode": {
|
"kilocode": {
|
||||||
"name": "Kilo Code",
|
"name": "Kilo Code",
|
||||||
"folder": ".kilocode/",
|
"folder": ".kilocode/",
|
||||||
|
"commands_subdir": "workflows", # Special: uses workflows/ not commands/
|
||||||
"install_url": None, # IDE-based
|
"install_url": None, # IDE-based
|
||||||
"requires_cli": False,
|
"requires_cli": False,
|
||||||
},
|
},
|
||||||
"auggie": {
|
"auggie": {
|
||||||
"name": "Auggie CLI",
|
"name": "Auggie CLI",
|
||||||
"folder": ".augment/",
|
"folder": ".augment/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": "https://docs.augmentcode.com/cli/setup-auggie/install-auggie-cli",
|
"install_url": "https://docs.augmentcode.com/cli/setup-auggie/install-auggie-cli",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"codebuddy": {
|
"codebuddy": {
|
||||||
"name": "CodeBuddy",
|
"name": "CodeBuddy",
|
||||||
"folder": ".codebuddy/",
|
"folder": ".codebuddy/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": "https://www.codebuddy.ai/cli",
|
"install_url": "https://www.codebuddy.ai/cli",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"qodercli": {
|
"qodercli": {
|
||||||
"name": "Qoder CLI",
|
"name": "Qoder CLI",
|
||||||
"folder": ".qoder/",
|
"folder": ".qoder/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": "https://qoder.com/cli",
|
"install_url": "https://qoder.com/cli",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"roo": {
|
"roo": {
|
||||||
"name": "Roo Code",
|
"name": "Roo Code",
|
||||||
"folder": ".roo/",
|
"folder": ".roo/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": None, # IDE-based
|
"install_url": None, # IDE-based
|
||||||
"requires_cli": False,
|
"requires_cli": False,
|
||||||
},
|
},
|
||||||
"q": {
|
"q": {
|
||||||
"name": "Amazon Q Developer CLI",
|
"name": "Amazon Q Developer CLI",
|
||||||
"folder": ".amazonq/",
|
"folder": ".amazonq/",
|
||||||
|
"commands_subdir": "prompts", # Special: uses prompts/ not commands/
|
||||||
"install_url": "https://aws.amazon.com/developer/learning/q-developer-cli/",
|
"install_url": "https://aws.amazon.com/developer/learning/q-developer-cli/",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"amp": {
|
"amp": {
|
||||||
"name": "Amp",
|
"name": "Amp",
|
||||||
"folder": ".agents/",
|
"folder": ".agents/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": "https://ampcode.com/manual#install",
|
"install_url": "https://ampcode.com/manual#install",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"shai": {
|
"shai": {
|
||||||
"name": "SHAI",
|
"name": "SHAI",
|
||||||
"folder": ".shai/",
|
"folder": ".shai/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": "https://github.com/ovh/shai",
|
"install_url": "https://github.com/ovh/shai",
|
||||||
"requires_cli": True,
|
"requires_cli": True,
|
||||||
},
|
},
|
||||||
"agy": {
|
"agy": {
|
||||||
"name": "Antigravity",
|
"name": "Antigravity",
|
||||||
"folder": ".agent/",
|
"folder": ".agent/",
|
||||||
|
"commands_subdir": "workflows", # Special: uses workflows/ not commands/
|
||||||
"install_url": None, # IDE-based
|
"install_url": None, # IDE-based
|
||||||
"requires_cli": False,
|
"requires_cli": False,
|
||||||
},
|
},
|
||||||
"bob": {
|
"bob": {
|
||||||
"name": "IBM Bob",
|
"name": "IBM Bob",
|
||||||
"folder": ".bob/",
|
"folder": ".bob/",
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": None, # IDE-based
|
"install_url": None, # IDE-based
|
||||||
"requires_cli": False,
|
"requires_cli": False,
|
||||||
},
|
},
|
||||||
"generic": {
|
"generic": {
|
||||||
"name": "Generic (bring your own agent)",
|
"name": "Generic (bring your own agent)",
|
||||||
"folder": None, # Set dynamically via --ai-commands-dir
|
"folder": None, # Set dynamically via --ai-commands-dir
|
||||||
|
"commands_subdir": "commands",
|
||||||
"install_url": None,
|
"install_url": None,
|
||||||
"requires_cli": False,
|
"requires_cli": False,
|
||||||
},
|
},
|
||||||
@@ -1056,10 +1075,11 @@ def install_ai_skills(project_path: Path, selected_ai: str, tracker: StepTracker
|
|||||||
# download_and_extract_template() already placed the .md files here.
|
# download_and_extract_template() already placed the .md files here.
|
||||||
agent_config = AGENT_CONFIG.get(selected_ai, {})
|
agent_config = AGENT_CONFIG.get(selected_ai, {})
|
||||||
agent_folder = agent_config.get("folder", "")
|
agent_folder = agent_config.get("folder", "")
|
||||||
|
commands_subdir = agent_config.get("commands_subdir", "commands")
|
||||||
if agent_folder:
|
if agent_folder:
|
||||||
templates_dir = project_path / agent_folder.rstrip("/") / "commands"
|
templates_dir = project_path / agent_folder.rstrip("/") / commands_subdir
|
||||||
else:
|
else:
|
||||||
templates_dir = project_path / "commands"
|
templates_dir = project_path / commands_subdir
|
||||||
|
|
||||||
if not templates_dir.exists() or not any(templates_dir.glob("*.md")):
|
if not templates_dir.exists() or not any(templates_dir.glob("*.md")):
|
||||||
# Fallback: try the repo-relative path (for running from source checkout)
|
# Fallback: try the repo-relative path (for running from source checkout)
|
||||||
@@ -1236,6 +1256,20 @@ def init(
|
|||||||
|
|
||||||
show_banner()
|
show_banner()
|
||||||
|
|
||||||
|
# Detect when option values are likely misinterpreted flags (parameter ordering issue)
|
||||||
|
if ai_assistant and ai_assistant.startswith("--"):
|
||||||
|
console.print(f"[red]Error:[/red] Invalid value for --ai: '{ai_assistant}'")
|
||||||
|
console.print("[yellow]Hint:[/yellow] Did you forget to provide a value for --ai?")
|
||||||
|
console.print("[yellow]Example:[/yellow] specify init --ai claude --here")
|
||||||
|
console.print(f"[yellow]Available agents:[/yellow] {', '.join(AGENT_CONFIG.keys())}")
|
||||||
|
raise typer.Exit(1)
|
||||||
|
|
||||||
|
if ai_commands_dir and ai_commands_dir.startswith("--"):
|
||||||
|
console.print(f"[red]Error:[/red] Invalid value for --ai-commands-dir: '{ai_commands_dir}'")
|
||||||
|
console.print("[yellow]Hint:[/yellow] Did you forget to provide a value for --ai-commands-dir?")
|
||||||
|
console.print("[yellow]Example:[/yellow] specify init --ai generic --ai-commands-dir .myagent/commands/")
|
||||||
|
raise typer.Exit(1)
|
||||||
|
|
||||||
if project_name == ".":
|
if project_name == ".":
|
||||||
here = True
|
here = True
|
||||||
project_name = None # Clear project_name to use existing validation logic
|
project_name = None # Clear project_name to use existing validation logic
|
||||||
|
|||||||
@@ -630,3 +630,65 @@ class TestCliValidation:
|
|||||||
plain = re.sub(r'\x1b\[[0-9;]*m', '', result.output)
|
plain = re.sub(r'\x1b\[[0-9;]*m', '', result.output)
|
||||||
assert "--ai-skills" in plain
|
assert "--ai-skills" in plain
|
||||||
assert "agent skills" in plain.lower()
|
assert "agent skills" in plain.lower()
|
||||||
|
|
||||||
|
|
||||||
|
class TestParameterOrderingIssue:
|
||||||
|
"""Test fix for GitHub issue #1641: parameter ordering issues."""
|
||||||
|
|
||||||
|
def test_ai_flag_consuming_here_flag(self):
|
||||||
|
"""--ai without value should not consume --here flag (issue #1641)."""
|
||||||
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
# This used to fail with "Must specify project name" because --here was consumed by --ai
|
||||||
|
result = runner.invoke(app, ["init", "--ai-skills", "--ai", "--here"])
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
assert "Invalid value for --ai" in result.output
|
||||||
|
assert "--here" in result.output # Should mention the invalid value
|
||||||
|
|
||||||
|
def test_ai_flag_consuming_ai_skills_flag(self):
|
||||||
|
"""--ai without value should not consume --ai-skills flag."""
|
||||||
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
# This should fail with helpful error about missing --ai value
|
||||||
|
result = runner.invoke(app, ["init", "--here", "--ai", "--ai-skills"])
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
assert "Invalid value for --ai" in result.output
|
||||||
|
assert "--ai-skills" in result.output # Should mention the invalid value
|
||||||
|
|
||||||
|
def test_error_message_provides_hint(self):
|
||||||
|
"""Error message should provide helpful hint about missing value."""
|
||||||
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
result = runner.invoke(app, ["init", "--ai", "--here"])
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
assert "Hint:" in result.output or "hint" in result.output.lower()
|
||||||
|
assert "forget to provide a value" in result.output.lower()
|
||||||
|
|
||||||
|
def test_error_message_lists_available_agents(self):
|
||||||
|
"""Error message should list available agents."""
|
||||||
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
result = runner.invoke(app, ["init", "--ai", "--here"])
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
# Should mention some known agents
|
||||||
|
output_lower = result.output.lower()
|
||||||
|
assert any(agent in output_lower for agent in ["claude", "copilot", "gemini"])
|
||||||
|
|
||||||
|
def test_ai_commands_dir_consuming_flag(self):
|
||||||
|
"""--ai-commands-dir without value should not consume next flag."""
|
||||||
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
result = runner.invoke(app, ["init", "myproject", "--ai", "generic", "--ai-commands-dir", "--here"])
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
assert "Invalid value for --ai-commands-dir" in result.output
|
||||||
|
assert "--here" in result.output
|
||||||
|
|||||||
Reference in New Issue
Block a user