Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3b456c4c8 | ||
|
|
e04175b51e | ||
|
|
cc75a22e45 | ||
|
|
b2f749ef41 | ||
|
|
321edbc62e | ||
|
|
fadd250a98 | ||
|
|
9ff9c9fd8d | ||
|
|
45f04abd38 | ||
|
|
1c0e7d14d5 | ||
|
|
55555eb39e | ||
|
|
8bbacd4adb | ||
|
|
6a3e81f813 | ||
|
|
eb3c63fe0f | ||
|
|
68eba52a40 | ||
|
|
721ecc9bec | ||
|
|
df3e4930cc | ||
|
|
f3d55cff84 | ||
|
|
c6051a0b8a | ||
|
|
04cb5f00d4 | ||
|
|
e924a73625 | ||
|
|
e642acaea4 |
@@ -7,6 +7,12 @@ All notable changes to the Specify CLI will be documented in this file.
|
||||
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).
|
||||
|
||||
## [LATEST_VERSION] - RELEASE_DATE
|
||||
|
||||
### Added
|
||||
|
||||
- Support for using `.` as a shorthand for current directory in `specify init .` command, equivalent to `--here` flag but more intuitive for users
|
||||
|
||||
## [0.0.17] - 2025-09-22
|
||||
|
||||
### Added
|
||||
|
||||
50
README.md
50
README.md
@@ -150,13 +150,13 @@ The `specify` command supports the following options:
|
||||
|
||||
| Argument/Option | Type | Description |
|
||||
|------------------------|----------|------------------------------------------------------------------------------|
|
||||
| `<project-name>` | Argument | Name for your new project directory (optional if using `--here`) |
|
||||
| `<project-name>` | 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`, `qwen`, `opencode`, `codex`, `windsurf`, `kilocode`, `auggie`, or `roo` |
|
||||
| `--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 |
|
||||
| `--no-git` | Flag | Skip git repository initialization |
|
||||
| `--here` | Flag | Initialize project in the current directory instead of creating a new one |
|
||||
| `--force` | Flag | Force merge/overwrite when using `--here` in a non-empty directory (skip confirmation) |
|
||||
| `--force` | Flag | Force merge/overwrite when initializing in current directory (skip confirmation) |
|
||||
| `--skip-tls` | Flag | Skip SSL/TLS verification (not recommended) |
|
||||
| `--debug` | Flag | Enable detailed debug output for troubleshooting |
|
||||
| `--github-token` | Option | GitHub token for API requests (or set GH_TOKEN/GITHUB_TOKEN env variable) |
|
||||
@@ -180,9 +180,13 @@ specify init my-project --ai windsurf
|
||||
specify init my-project --ai copilot --script ps
|
||||
|
||||
# Initialize in current directory
|
||||
specify init . --ai copilot
|
||||
# or use the --here flag
|
||||
specify init --here --ai copilot
|
||||
|
||||
# Force merge into current (non-empty) directory without confirmation
|
||||
specify init . --force --ai copilot
|
||||
# or
|
||||
specify init --here --force --ai copilot
|
||||
|
||||
# Skip git initialization
|
||||
@@ -292,8 +296,12 @@ specify init <project_name>
|
||||
Or initialize in the current directory:
|
||||
|
||||
```bash
|
||||
specify init .
|
||||
# or use the --here flag
|
||||
specify init --here
|
||||
# Skip confirmation when the directory already has files
|
||||
specify init . --force
|
||||
# or
|
||||
specify init --here --force
|
||||
```
|
||||
|
||||
@@ -311,9 +319,14 @@ specify init <project_name> --ai opencode
|
||||
specify init <project_name> --ai codex
|
||||
specify init <project_name> --ai windsurf
|
||||
# Or in current directory:
|
||||
specify init . --ai claude
|
||||
specify init . --ai codex
|
||||
# or use --here flag
|
||||
specify init --here --ai claude
|
||||
specify init --here --ai codex
|
||||
# Force merge into a non-empty current directory
|
||||
specify init . --force --ai claude
|
||||
# or
|
||||
specify init --here --force --ai claude
|
||||
```
|
||||
|
||||
@@ -337,7 +350,7 @@ The first step should be establishing your project's governing principles using
|
||||
/constitution Create principles focused on code quality, testing standards, user experience consistency, and performance requirements. Include governance for how these principles should guide technical decisions and implementation choices.
|
||||
```
|
||||
|
||||
This step creates or updates the `/memory/constitution.md` file with your project's foundational guidelines that the AI agent will reference during specification, planning, and implementation phases.
|
||||
This step creates or updates the `.specify/memory/constitution.md` file with your project's foundational guidelines that the AI agent will reference during specification, planning, and implementation phases.
|
||||
|
||||
### **STEP 2:** Create project specifications
|
||||
|
||||
@@ -376,21 +389,22 @@ The produced specification should contain a set of user stories and functional r
|
||||
At this stage, your project folder contents should resemble the following:
|
||||
|
||||
```text
|
||||
├── memory
|
||||
│ └── constitution.md
|
||||
├── scripts
|
||||
│ ├── check-prerequisites.sh
|
||||
│ ├── common.sh
|
||||
│ ├── create-new-feature.sh
|
||||
│ ├── setup-plan.sh
|
||||
│ └── update-claude-md.sh
|
||||
├── specs
|
||||
│ └── 001-create-taskify
|
||||
│ └── spec.md
|
||||
└── templates
|
||||
├── plan-template.md
|
||||
├── spec-template.md
|
||||
└── tasks-template.md
|
||||
└── .specify
|
||||
├── memory
|
||||
│ └── constitution.md
|
||||
├── scripts
|
||||
│ ├── check-prerequisites.sh
|
||||
│ ├── common.sh
|
||||
│ ├── create-new-feature.sh
|
||||
│ ├── setup-plan.sh
|
||||
│ └── update-claude-md.sh
|
||||
├── specs
|
||||
│ └── 001-create-taskify
|
||||
│ └── spec.md
|
||||
└── templates
|
||||
├── plan-template.md
|
||||
├── spec-template.md
|
||||
└── tasks-template.md
|
||||
```
|
||||
|
||||
### **STEP 3:** Functional specification clarification (required before planning)
|
||||
|
||||
@@ -55,8 +55,8 @@ Our research and experimentation focus on:
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see our [Contributing Guide](CONTRIBUTING.md) for information on how to contribute to this project.
|
||||
Please see our [Contributing Guide](https://github.com/github/spec-kit/blob/main/CONTRIBUTING.md) for information on how to contribute to this project.
|
||||
|
||||
## Support
|
||||
|
||||
For support, please check our [Support Guide](SUPPORT.md) or open an issue on GitHub.
|
||||
For support, please check our [Support Guide](https://github.com/github/spec-kit/blob/main/SUPPORT.md) or open an issue on GitHub.
|
||||
|
||||
@@ -21,6 +21,8 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME
|
||||
Or initialize in the current directory:
|
||||
|
||||
```bash
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init .
|
||||
# or use the --here flag
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init --here
|
||||
```
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ fi
|
||||
FEATURE_DIR="$SPECS_DIR/$BRANCH_NAME"
|
||||
mkdir -p "$FEATURE_DIR"
|
||||
|
||||
TEMPLATE="$REPO_ROOT/templates/spec-template.md"
|
||||
TEMPLATE="$REPO_ROOT/.specify/templates/spec-template.md"
|
||||
SPEC_FILE="$FEATURE_DIR/spec.md"
|
||||
if [ -f "$TEMPLATE" ]; then cp "$TEMPLATE" "$SPEC_FILE"; else touch "$SPEC_FILE"; fi
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ if ($hasGit) {
|
||||
$featureDir = Join-Path $specsDir $branchName
|
||||
New-Item -ItemType Directory -Path $featureDir -Force | Out-Null
|
||||
|
||||
$template = Join-Path $repoRoot 'templates/spec-template.md'
|
||||
$template = Join-Path $repoRoot '.specify/templates/spec-template.md'
|
||||
$specFile = Join-Path $featureDir 'spec.md'
|
||||
if (Test-Path $template) {
|
||||
Copy-Item $template $specFile -Force
|
||||
|
||||
@@ -124,7 +124,7 @@ function Extract-PlanField {
|
||||
if (-not (Test-Path $PlanFile)) { return '' }
|
||||
# Lines like **Language/Version**: Python 3.12
|
||||
$regex = "^\*\*$([Regex]::Escape($FieldPattern))\*\*: (.+)$"
|
||||
Get-Content -LiteralPath $PlanFile | ForEach-Object {
|
||||
Get-Content -LiteralPath $PlanFile -Encoding utf8 | ForEach-Object {
|
||||
if ($_ -match $regex) {
|
||||
$val = $Matches[1].Trim()
|
||||
if ($val -notin @('NEEDS CLARIFICATION','N/A')) { return $val }
|
||||
@@ -215,7 +215,7 @@ function New-AgentFile {
|
||||
$escaped_framework = $NEW_FRAMEWORK
|
||||
$escaped_branch = $CURRENT_BRANCH
|
||||
|
||||
$content = Get-Content -LiteralPath $temp -Raw
|
||||
$content = Get-Content -LiteralPath $temp -Raw -Encoding utf8
|
||||
$content = $content -replace '\[PROJECT NAME\]',$ProjectName
|
||||
$content = $content -replace '\[DATE\]',$Date.ToString('yyyy-MM-dd')
|
||||
|
||||
@@ -253,7 +253,7 @@ function New-AgentFile {
|
||||
|
||||
$parent = Split-Path -Parent $TargetFile
|
||||
if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent | Out-Null }
|
||||
Set-Content -LiteralPath $TargetFile -Value $content -NoNewline
|
||||
Set-Content -LiteralPath $TargetFile -Value $content -NoNewline -Encoding utf8
|
||||
Remove-Item $temp -Force
|
||||
return $true
|
||||
}
|
||||
@@ -285,7 +285,7 @@ function Update-ExistingAgentFile {
|
||||
if ($techStack) { $newChangeEntry = "- ${CURRENT_BRANCH}: Added ${techStack}" }
|
||||
elseif ($NEW_DB -and $NEW_DB -notin @('N/A','NEEDS CLARIFICATION')) { $newChangeEntry = "- ${CURRENT_BRANCH}: Added ${NEW_DB}" }
|
||||
|
||||
$lines = Get-Content -LiteralPath $TargetFile
|
||||
$lines = Get-Content -LiteralPath $TargetFile -Encoding utf8
|
||||
$output = New-Object System.Collections.Generic.List[string]
|
||||
$inTech = $false; $inChanges = $false; $techAdded = $false; $changeAdded = $false; $existingChanges = 0
|
||||
|
||||
@@ -327,7 +327,7 @@ function Update-ExistingAgentFile {
|
||||
$newTechEntries | ForEach-Object { $output.Add($_) }
|
||||
}
|
||||
|
||||
Set-Content -LiteralPath $TargetFile -Value ($output -join [Environment]::NewLine)
|
||||
Set-Content -LiteralPath $TargetFile -Value ($output -join [Environment]::NewLine) -Encoding utf8
|
||||
return $true
|
||||
}
|
||||
|
||||
|
||||
@@ -14,11 +14,13 @@ Specify CLI - Setup tool for Specify projects
|
||||
|
||||
Usage:
|
||||
uvx specify-cli.py init <project-name>
|
||||
uvx specify-cli.py init .
|
||||
uvx specify-cli.py init --here
|
||||
|
||||
Or install globally:
|
||||
uv tool install --from specify-cli.py specify-cli
|
||||
specify init <project-name>
|
||||
specify init .
|
||||
specify init --here
|
||||
"""
|
||||
|
||||
@@ -192,9 +194,9 @@ def get_key():
|
||||
key = readchar.readkey()
|
||||
|
||||
# Arrow keys
|
||||
if key == readchar.key.UP:
|
||||
if key == readchar.key.UP or key == readchar.key.CTRL_P:
|
||||
return 'up'
|
||||
if key == readchar.key.DOWN:
|
||||
if key == readchar.key.DOWN or key == readchar.key.CTRL_N:
|
||||
return 'down'
|
||||
|
||||
# Enter/Return
|
||||
@@ -747,7 +749,7 @@ def ensure_executable_scripts(project_path: Path, tracker: StepTracker | None =
|
||||
|
||||
@app.command()
|
||||
def init(
|
||||
project_name: str = typer.Argument(None, help="Name for your new project directory (optional if using --here)"),
|
||||
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, qwen, opencode, codex, windsurf, kilocode, or auggie"),
|
||||
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"),
|
||||
@@ -781,7 +783,9 @@ def init(
|
||||
specify init my-project --ai windsurf
|
||||
specify init my-project --ai auggie
|
||||
specify init --ignore-agent-tools my-project
|
||||
specify init --here --ai claude
|
||||
specify init . --ai claude # Initialize in current directory
|
||||
specify init . # Initialize in current directory (interactive AI selection)
|
||||
specify init --here --ai claude # Alternative syntax for current directory
|
||||
specify init --here --ai codex
|
||||
specify init --here
|
||||
specify init --here --force # Skip confirmation when current directory not empty
|
||||
@@ -789,13 +793,18 @@ def init(
|
||||
# Show banner first
|
||||
show_banner()
|
||||
|
||||
# Handle '.' as shorthand for current directory (equivalent to --here)
|
||||
if project_name == ".":
|
||||
here = True
|
||||
project_name = None # Clear project_name to use existing validation logic
|
||||
|
||||
# Validate arguments
|
||||
if here and project_name:
|
||||
console.print("[red]Error:[/red] Cannot specify both project name and --here flag")
|
||||
raise typer.Exit(1)
|
||||
|
||||
if not here and not project_name:
|
||||
console.print("[red]Error:[/red] Must specify either a project name or use --here flag")
|
||||
console.print("[red]Error:[/red] Must specify either a project name, use '.' for current directory, or use --here flag")
|
||||
raise typer.Exit(1)
|
||||
|
||||
# Determine project directory
|
||||
@@ -1070,7 +1079,7 @@ def init(
|
||||
console.print(steps_panel)
|
||||
|
||||
enhancement_lines = [
|
||||
"Optional commands that you can use for your specs (improve quality & confidence)[/bright_black]",
|
||||
"Optional commands that you can use for your specs [bright_black](improve quality & confidence)[/bright_black]",
|
||||
"",
|
||||
f"○ [cyan]/clarify[/] [bright_black](optional)[/bright_black] - Ask structured questions to de-risk ambiguous areas before planning (run before [cyan]/plan[/] if used)",
|
||||
f"○ [cyan]/analyze[/] [bright_black](optional)[/bright_black] - Cross-artifact consistency & alignment report (after [cyan]/tasks[/], before [cyan]/implement[/])"
|
||||
|
||||
@@ -15,7 +15,7 @@ scripts:
|
||||
1. Load feature spec from Input path
|
||||
→ If not found: ERROR "No feature spec at {path}"
|
||||
2. Fill Technical Context (scan for NEEDS CLARIFICATION)
|
||||
→ Detect Project Type from context (web=frontend+backend, mobile=app+api)
|
||||
→ Detect Project Type from file system structure or context (web=frontend+backend, mobile=app+api)
|
||||
→ Set Structure Decision based on project type
|
||||
3. Fill the Constitution Check section based on the content of the constitution document.
|
||||
4. Evaluate Constitution Check section below
|
||||
@@ -69,8 +69,14 @@ specs/[###-feature]/
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
<!--
|
||||
ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
|
||||
for this feature. Delete unused options and expand the chosen structure with
|
||||
real paths (e.g., apps/admin, packages/something). The delivered plan must
|
||||
not include Option labels.
|
||||
-->
|
||||
```
|
||||
# Option 1: Single project (DEFAULT)
|
||||
# [REMOVE IF UNUSED] Option 1: Single project (DEFAULT)
|
||||
src/
|
||||
├── models/
|
||||
├── services/
|
||||
@@ -82,7 +88,7 @@ tests/
|
||||
├── integration/
|
||||
└── unit/
|
||||
|
||||
# Option 2: Web application (when "frontend" + "backend" detected)
|
||||
# [REMOVE IF UNUSED] Option 2: Web application (when "frontend" + "backend" detected)
|
||||
backend/
|
||||
├── src/
|
||||
│ ├── models/
|
||||
@@ -97,15 +103,16 @@ frontend/
|
||||
│ └── services/
|
||||
└── tests/
|
||||
|
||||
# Option 3: Mobile + API (when "iOS/Android" detected)
|
||||
# [REMOVE IF UNUSED] Option 3: Mobile + API (when "iOS/Android" detected)
|
||||
api/
|
||||
└── [same as backend above]
|
||||
|
||||
ios/ or android/
|
||||
└── [platform-specific structure]
|
||||
└── [platform-specific structure: feature modules, UI flows, platform tests]
|
||||
```
|
||||
|
||||
**Structure Decision**: [DEFAULT to Option 1 unless Technical Context indicates web/mobile app]
|
||||
**Structure Decision**: [Document the selected structure and reference the real
|
||||
directories captured above]
|
||||
|
||||
## Phase 0: Outline & Research
|
||||
1. **Extract unknowns from Technical Context** above:
|
||||
|
||||
Reference in New Issue
Block a user