Compare commits

...

16 Commits

Author SHA1 Message Date
Den Delimarsky
3e85f46465 Merge pull request #910 from zidoshare/create-new-feature
fix: correct argument parsing in create-new-feature.sh script
2025-10-18 20:04:53 -07:00
Den Delimarsky
015440838a Merge branch 'main' into create-new-feature 2025-10-18 20:04:37 -07:00
Den Delimarsky
7050a3151c Merge pull request #918 from wfongcn/patch-1
Change loop condition to include last argument
2025-10-18 20:03:39 -07:00
Den Delimarsky
9e84f46e56 Merge pull request #929 from isdaniel/fix/ide-agent-cli-checks
fix: Skip CLI checks for IDE-based agents in check command
2025-10-18 20:03:14 -07:00
Den Delimarsky
5e32de1f3f Merge pull request #904 from zidoshare/main
Fix: incorrect command formatting in agent context file, refix #895
2025-10-18 18:32:51 -07:00
Den Delimarsky
5558b24475 Merge pull request #934 from JackieQi/main
fix: broken media files
2025-10-18 18:30:19 -07:00
Jackie Qi
f892b9e1cb fix: broken media files 2025-10-17 13:04:27 -07:00
Den Delimarsky
a66af9b7f5 Merge pull request #914 from isdaniel/smart-merge-settings.json
Smart JSON Merging for VS Code Settings `.vscode/settings.json`
2025-10-17 10:42:29 -07:00
Den Delimarsky
a5fdd53a3e Merge pull request #930 from lutzroeder/main
Update README.md
2025-10-17 10:39:29 -07:00
Lutz Roeder
ed0fa8fffe Update README.md 2025-10-17 10:25:36 -07:00
danielshih
098380a46f fix: Skip CLI checks for IDE-based agents in check command
- Add requires_cli field handling to check() command
- IDE-based agents (copilot, cursor-agent, windsurf, kilocode, roo) now properly skip CLI checks
- Prevents false errors when checking for IDE-integrated agents that don't require CLI tools
2025-10-17 23:53:47 +08:00
Peter Wang
74f7e508a4 Change loop condition to include last argument
The last argument is not processed. 
e.g. create-new-feature.sh -h doesn't show the help information.
2025-10-17 09:03:47 +08:00
danielshih
8130d98bcc The function parameters lack type hints. Consider adding type annotations for better code clarity and IDE support. 2025-10-17 00:24:28 +08:00
danielshih
315269d9a8 - **Smart JSON Merging for VS Code Settings**: .vscode/settings.json is now intelligently merged instead of being overwritten during specify init --here or specify init .
- Existing settings are preserved
  - New Spec Kit settings are added
  - Nested objects are merged recursively
  - Prevents accidental loss of custom VS Code workspace configurations
2025-10-17 00:16:04 +08:00
hongxuww
b37a9516d0 fix: correct argument parsing in create-new-feature.sh script
Fix two critical bugs in the argument parsing logic that caused incorrect
behavior when --short-name parameter was used:

1. **Index offset bug**: The loop started at i=0 and used i < $#, which
   incorrectly processed $0 (script name) as the first argument and
   skipped the last actual parameter. Changed to i=1 and i <= $# to
   properly iterate through actual command-line arguments ($1 to $#).

2. **Boundary condition bug**: The condition `[ $((i + 1)) -ge $# ]`
   incorrectly flagged valid arguments as missing. When --short-name was
   at position $#-1, the next position $# was valid but treated as
   out-of-bounds. Changed to `[ $((i + 1)) -gt $# ]` for correct validation.

3. **Enhanced validation**: Added check to ensure --short-name value is
   not another option (doesn't start with --).

**Before**:
- `script --json "desc" --short-name "test"` → Error: requires a value
- `script --json "desc1" "desc2" --short-name` → Generated wrong branch name

**After**:
- `script --json "desc" --short-name "test"` → Works correctly
- `script --json "desc1" "desc2" --short-name` → Proper error message

This ensures the script correctly supports both parameter orders:
- `[--json] [--short-name <name>] <feature_description>`
- `[--json] <feature_description> [--short-name <name>]`
2025-10-16 10:02:53 +00:00
hongxuww
03c7021270 Fix: incorrect command formatting in agent context file, refix #895 2025-10-16 02:11:48 +00:00
9 changed files with 98 additions and 12 deletions

View File

@@ -84,6 +84,8 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME
### 2. Establish project principles ### 2. Establish project principles
Launch your AI assistant in the project directory. The `/speckit.*` commands are available in the assistant.
Use the **`/speckit.constitution`** command to create your project's governing principles and development guidelines that will guide all subsequent development. Use the **`/speckit.constitution`** command to create your project's governing principles and development guidelines that will guide all subsequent development.
```bash ```bash

Binary file not shown.

Before

Width:  |  Height:  |  Size: 529 KiB

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

@@ -5,20 +5,26 @@ set -e
JSON_MODE=false JSON_MODE=false
SHORT_NAME="" SHORT_NAME=""
ARGS=() ARGS=()
i=0 i=1
while [ $i -lt $# ]; do while [ $i -le $# ]; do
arg="${!i}" arg="${!i}"
case "$arg" in case "$arg" in
--json) --json)
JSON_MODE=true JSON_MODE=true
;; ;;
--short-name) --short-name)
if [ $((i + 1)) -ge $# ]; then if [ $((i + 1)) -gt $# ]; then
echo 'Error: --short-name requires a value' >&2 echo 'Error: --short-name requires a value' >&2
exit 1 exit 1
fi fi
i=$((i + 1)) i=$((i + 1))
SHORT_NAME="${!i}" next_arg="${!i}"
# Check if the next argument is another option (starts with --)
if [[ "$next_arg" == --* ]]; then
echo 'Error: --short-name requires a value' >&2
exit 1
fi
SHORT_NAME="$next_arg"
;; ;;
--help|-h) --help|-h)
echo "Usage: $0 [--json] [--short-name <name>] <feature_description>" echo "Usage: $0 [--json] [--short-name <name>] <feature_description>"

View File

@@ -250,7 +250,7 @@ get_commands_for_language() {
echo "cargo test && cargo clippy" echo "cargo test && cargo clippy"
;; ;;
*"JavaScript"*|*"TypeScript"*) *"JavaScript"*|*"TypeScript"*)
echo "npm test \&\& npm run lint" echo "npm test \\&\\& npm run lint"
;; ;;
*) *)
echo "# Add commands for $lang" echo "# Add commands for $lang"

View File

@@ -485,6 +485,73 @@ def init_git_repo(project_path: Path, quiet: bool = False) -> Tuple[bool, Option
finally: finally:
os.chdir(original_cwd) os.chdir(original_cwd)
def handle_vscode_settings(sub_item, dest_file, rel_path, verbose=False, tracker=None) -> None:
"""Handle merging or copying of .vscode/settings.json files."""
def log(message, color="green"):
if verbose and not tracker:
console.print(f"[{color}]{message}[/] {rel_path}")
try:
with open(sub_item, 'r', encoding='utf-8') as f:
new_settings = json.load(f)
if dest_file.exists():
merged = merge_json_files(dest_file, new_settings, verbose=verbose and not tracker)
with open(dest_file, 'w', encoding='utf-8') as f:
json.dump(merged, f, indent=4)
f.write('\n')
log("Merged:", "green")
else:
shutil.copy2(sub_item, dest_file)
log("Copied (no existing settings.json):", "blue")
except Exception as e:
log(f"Warning: Could not merge, copying instead: {e}", "yellow")
shutil.copy2(sub_item, dest_file)
def merge_json_files(existing_path: Path, new_content: dict, verbose: bool = False) -> dict:
"""Merge new JSON content into existing JSON file.
Performs a deep merge where:
- New keys are added
- Existing keys are preserved unless overwritten by new content
- Nested dictionaries are merged recursively
- Lists and other values are replaced (not merged)
Args:
existing_path: Path to existing JSON file
new_content: New JSON content to merge in
verbose: Whether to print merge details
Returns:
Merged JSON content as dict
"""
try:
with open(existing_path, 'r', encoding='utf-8') as f:
existing_content = json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
# If file doesn't exist or is invalid, just use new content
return new_content
def deep_merge(base: dict, update: dict) -> dict:
"""Recursively merge update dict into base dict."""
result = base.copy()
for key, value in update.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
# Recursively merge nested dictionaries
result[key] = deep_merge(result[key], value)
else:
# Add new key or replace existing value
result[key] = value
return result
merged = deep_merge(existing_content, new_content)
if verbose:
console.print(f"[cyan]Merged JSON file:[/cyan] {existing_path.name}")
return merged
def download_template_from_github(ai_assistant: str, download_dir: Path, *, script_type: str = "sh", verbose: bool = True, show_progress: bool = True, client: httpx.Client = None, debug: bool = False, github_token: str = None) -> Tuple[Path, dict]: def download_template_from_github(ai_assistant: str, download_dir: Path, *, script_type: str = "sh", verbose: bool = True, show_progress: bool = True, client: httpx.Client = None, debug: bool = False, github_token: str = None) -> Tuple[Path, dict]:
repo_owner = "github" repo_owner = "github"
repo_name = "spec-kit" repo_name = "spec-kit"
@@ -676,7 +743,11 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
rel_path = sub_item.relative_to(item) rel_path = sub_item.relative_to(item)
dest_file = dest_path / rel_path dest_file = dest_path / rel_path
dest_file.parent.mkdir(parents=True, exist_ok=True) dest_file.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(sub_item, dest_file) # Special handling for .vscode/settings.json - merge instead of overwrite
if dest_file.name == "settings.json" and dest_file.parent.name == ".vscode":
handle_vscode_settings(sub_item, dest_file, rel_path, verbose, tracker)
else:
shutil.copy2(sub_item, dest_file)
else: else:
shutil.copytree(item, dest_path) shutil.copytree(item, dest_path)
else: else:
@@ -1097,9 +1168,16 @@ def check():
agent_results = {} agent_results = {}
for agent_key, agent_config in AGENT_CONFIG.items(): for agent_key, agent_config in AGENT_CONFIG.items():
agent_name = agent_config["name"] agent_name = agent_config["name"]
requires_cli = agent_config["requires_cli"]
tracker.add(agent_key, agent_name) tracker.add(agent_key, agent_name)
agent_results[agent_key] = check_tool(agent_key, tracker=tracker)
if requires_cli:
agent_results[agent_key] = check_tool(agent_key, tracker=tracker)
else:
# IDE-based agent - skip CLI check and mark as optional
tracker.skip(agent_key, "IDE-based, no CLI check")
agent_results[agent_key] = False # Don't count IDE agents as "found"
# Check VS Code variants (not in agent config) # Check VS Code variants (not in agent config)
tracker.add("code", "Visual Studio Code") tracker.add("code", "Visual Studio Code")