Merge branch 'main' into create-new-feature

This commit is contained in:
Den Delimarsky
2025-10-18 20:04:37 -07:00
committed by GitHub
9 changed files with 88 additions and 8 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

@@ -203,4 +203,4 @@ else
echo "SPEC_FILE: $SPEC_FILE" echo "SPEC_FILE: $SPEC_FILE"
echo "FEATURE_NUM: $FEATURE_NUM" echo "FEATURE_NUM: $FEATURE_NUM"
echo "SPECIFY_FEATURE environment variable set to: $BRANCH_NAME" echo "SPECIFY_FEATURE environment variable set to: $BRANCH_NAME"
fi fi

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:
@@ -1093,18 +1164,25 @@ def check():
tracker.add("git", "Git version control") tracker.add("git", "Git version control")
git_ok = check_tool("git", tracker=tracker) git_ok = check_tool("git", tracker=tracker)
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")
code_ok = check_tool("code", tracker=tracker) code_ok = check_tool("code", tracker=tracker)
tracker.add("code-insiders", "Visual Studio Code Insiders") tracker.add("code-insiders", "Visual Studio Code Insiders")
code_insiders_ok = check_tool("code-insiders", tracker=tracker) code_insiders_ok = check_tool("code-insiders", tracker=tracker)