Skip to content

Commit 0154408

Browse files
authored
Merge branch 'main' into create-new-feature
2 parents b37a951 + 7050a31 commit 0154408

File tree

9 files changed

+88
-8
lines changed

9 files changed

+88
-8
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME
8484

8585
### 2. Establish project principles
8686

87+
Launch your AI assistant in the project directory. The `/speckit.*` commands are available in the assistant.
88+
8789
Use the **`/speckit.constitution`** command to create your project's governing principles and development guidelines that will guide all subsequent development.
8890

8991
```bash

media/bootstrap-claude-code.gif

-227 KB
Loading

media/logo_large.webp

-37.1 KB
Loading

media/logo_small.webp

-4.98 KB
Loading

media/spec-kit-video-header.jpg

-82.3 KB
Loading

media/specify_cli.gif

-1.3 MB
Loading

scripts/bash/create-new-feature.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,4 @@ else
203203
echo "SPEC_FILE: $SPEC_FILE"
204204
echo "FEATURE_NUM: $FEATURE_NUM"
205205
echo "SPECIFY_FEATURE environment variable set to: $BRANCH_NAME"
206-
fi
206+
fi

scripts/bash/update-agent-context.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ get_commands_for_language() {
250250
echo "cargo test && cargo clippy"
251251
;;
252252
*"JavaScript"*|*"TypeScript"*)
253-
echo "npm test \&\& npm run lint"
253+
echo "npm test \\&\\& npm run lint"
254254
;;
255255
*)
256256
echo "# Add commands for $lang"

src/specify_cli/__init__.py

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,73 @@ def init_git_repo(project_path: Path, quiet: bool = False) -> Tuple[bool, Option
485485
finally:
486486
os.chdir(original_cwd)
487487

488+
def handle_vscode_settings(sub_item, dest_file, rel_path, verbose=False, tracker=None) -> None:
489+
"""Handle merging or copying of .vscode/settings.json files."""
490+
def log(message, color="green"):
491+
if verbose and not tracker:
492+
console.print(f"[{color}]{message}[/] {rel_path}")
493+
494+
try:
495+
with open(sub_item, 'r', encoding='utf-8') as f:
496+
new_settings = json.load(f)
497+
498+
if dest_file.exists():
499+
merged = merge_json_files(dest_file, new_settings, verbose=verbose and not tracker)
500+
with open(dest_file, 'w', encoding='utf-8') as f:
501+
json.dump(merged, f, indent=4)
502+
f.write('\n')
503+
log("Merged:", "green")
504+
else:
505+
shutil.copy2(sub_item, dest_file)
506+
log("Copied (no existing settings.json):", "blue")
507+
508+
except Exception as e:
509+
log(f"Warning: Could not merge, copying instead: {e}", "yellow")
510+
shutil.copy2(sub_item, dest_file)
511+
512+
def merge_json_files(existing_path: Path, new_content: dict, verbose: bool = False) -> dict:
513+
"""Merge new JSON content into existing JSON file.
514+
515+
Performs a deep merge where:
516+
- New keys are added
517+
- Existing keys are preserved unless overwritten by new content
518+
- Nested dictionaries are merged recursively
519+
- Lists and other values are replaced (not merged)
520+
521+
Args:
522+
existing_path: Path to existing JSON file
523+
new_content: New JSON content to merge in
524+
verbose: Whether to print merge details
525+
526+
Returns:
527+
Merged JSON content as dict
528+
"""
529+
try:
530+
with open(existing_path, 'r', encoding='utf-8') as f:
531+
existing_content = json.load(f)
532+
except (FileNotFoundError, json.JSONDecodeError):
533+
# If file doesn't exist or is invalid, just use new content
534+
return new_content
535+
536+
def deep_merge(base: dict, update: dict) -> dict:
537+
"""Recursively merge update dict into base dict."""
538+
result = base.copy()
539+
for key, value in update.items():
540+
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
541+
# Recursively merge nested dictionaries
542+
result[key] = deep_merge(result[key], value)
543+
else:
544+
# Add new key or replace existing value
545+
result[key] = value
546+
return result
547+
548+
merged = deep_merge(existing_content, new_content)
549+
550+
if verbose:
551+
console.print(f"[cyan]Merged JSON file:[/cyan] {existing_path.name}")
552+
553+
return merged
554+
488555
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]:
489556
repo_owner = "github"
490557
repo_name = "spec-kit"
@@ -676,7 +743,11 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, script_
676743
rel_path = sub_item.relative_to(item)
677744
dest_file = dest_path / rel_path
678745
dest_file.parent.mkdir(parents=True, exist_ok=True)
679-
shutil.copy2(sub_item, dest_file)
746+
# Special handling for .vscode/settings.json - merge instead of overwrite
747+
if dest_file.name == "settings.json" and dest_file.parent.name == ".vscode":
748+
handle_vscode_settings(sub_item, dest_file, rel_path, verbose, tracker)
749+
else:
750+
shutil.copy2(sub_item, dest_file)
680751
else:
681752
shutil.copytree(item, dest_path)
682753
else:
@@ -1093,18 +1164,25 @@ def check():
10931164

10941165
tracker.add("git", "Git version control")
10951166
git_ok = check_tool("git", tracker=tracker)
1096-
1167+
10971168
agent_results = {}
10981169
for agent_key, agent_config in AGENT_CONFIG.items():
10991170
agent_name = agent_config["name"]
1100-
1171+
requires_cli = agent_config["requires_cli"]
1172+
11011173
tracker.add(agent_key, agent_name)
1102-
agent_results[agent_key] = check_tool(agent_key, tracker=tracker)
1103-
1174+
1175+
if requires_cli:
1176+
agent_results[agent_key] = check_tool(agent_key, tracker=tracker)
1177+
else:
1178+
# IDE-based agent - skip CLI check and mark as optional
1179+
tracker.skip(agent_key, "IDE-based, no CLI check")
1180+
agent_results[agent_key] = False # Don't count IDE agents as "found"
1181+
11041182
# Check VS Code variants (not in agent config)
11051183
tracker.add("code", "Visual Studio Code")
11061184
code_ok = check_tool("code", tracker=tracker)
1107-
1185+
11081186
tracker.add("code-insiders", "Visual Studio Code Insiders")
11091187
code_insiders_ok = check_tool("code-insiders", tracker=tracker)
11101188

0 commit comments

Comments
 (0)