Compare commits
27 Commits
localden/f
...
v0.0.70
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e32de1f3f | ||
|
|
5558b24475 | ||
|
|
f892b9e1cb | ||
|
|
a66af9b7f5 | ||
|
|
a5fdd53a3e | ||
|
|
ed0fa8fffe | ||
|
|
8130d98bcc | ||
|
|
315269d9a8 | ||
|
|
03c7021270 | ||
|
|
3b000fce4d | ||
|
|
c59595d065 | ||
|
|
1c16a68df2 | ||
|
|
39bf3e4d9a | ||
|
|
045696641a | ||
|
|
41690cd1d4 | ||
|
|
e45c469709 | ||
|
|
8c9e586662 | ||
|
|
ce844c6259 | ||
|
|
84b46cd1b9 | ||
|
|
0cca67fcd2 | ||
|
|
66fc4c292d | ||
|
|
2baae57b26 | ||
|
|
514b0548fe | ||
|
|
be7db635cc | ||
|
|
7b55522213 | ||
|
|
7ca792509b | ||
|
|
47e5f7c2e2 |
@@ -42,7 +42,7 @@ Specify supports multiple AI agents by generating agent-specific command files a
|
||||
| **Kilo Code** | `.kilocode/rules/` | Markdown | N/A (IDE-based) | Kilo Code IDE |
|
||||
| **Auggie CLI** | `.augment/rules/` | Markdown | `auggie` | Auggie CLI |
|
||||
| **Roo Code** | `.roo/rules/` | Markdown | N/A (IDE-based) | Roo Code IDE |
|
||||
| **CodeBuddy** | `.codebuddy/commands/` | Markdown | `codebuddy` | CodeBuddy |
|
||||
| **CodeBuddy CLI** | `.codebuddy/commands/` | Markdown | `codebuddy` | CodeBuddy CLI |
|
||||
| **Amazon Q Developer CLI** | `.amazonq/prompts/` | Markdown | `q` | Amazon Q Developer CLI |
|
||||
|
||||
### Step-by-Step Integration Guide
|
||||
@@ -249,7 +249,7 @@ Require a command-line tool to be installed:
|
||||
- **Cursor**: `cursor-agent` CLI
|
||||
- **Qwen Code**: `qwen` CLI
|
||||
- **opencode**: `opencode` CLI
|
||||
- **CodeBuddy**: `codebuddy` CLI
|
||||
- **CodeBuddy CLI**: `codebuddy` CLI
|
||||
|
||||
### IDE-Based Agents
|
||||
Work within integrated development environments:
|
||||
|
||||
28
README.md
@@ -20,16 +20,16 @@
|
||||
## Table of Contents
|
||||
|
||||
- [🤔 What is Spec-Driven Development?](#-what-is-spec-driven-development)
|
||||
- [⚡ Get started](#-get-started)
|
||||
- [⚡ Get Started](#-get-started)
|
||||
- [📽️ Video Overview](#️-video-overview)
|
||||
- [🤖 Supported AI Agents](#-supported-ai-agents)
|
||||
- [🔧 Specify CLI Reference](#-specify-cli-reference)
|
||||
- [📚 Core philosophy](#-core-philosophy)
|
||||
- [🌟 Development phases](#-development-phases)
|
||||
- [🎯 Experimental goals](#-experimental-goals)
|
||||
- [📚 Core Philosophy](#-core-philosophy)
|
||||
- [🌟 Development Phases](#-development-phases)
|
||||
- [🎯 Experimental Goals](#-experimental-goals)
|
||||
- [🔧 Prerequisites](#-prerequisites)
|
||||
- [📖 Learn more](#-learn-more)
|
||||
- [📋 Detailed process](#-detailed-process)
|
||||
- [📖 Learn More](#-learn-more)
|
||||
- [📋 Detailed Process](#-detailed-process)
|
||||
- [🔍 Troubleshooting](#-troubleshooting)
|
||||
- [👥 Maintainers](#-maintainers)
|
||||
- [💬 Support](#-support)
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
Spec-Driven Development **flips the script** on traditional software development. For decades, code has been king — specifications were just scaffolding we built and discarded once the "real work" of coding began. Spec-Driven Development changes this: **specifications become executable**, directly generating working implementations rather than just guiding them.
|
||||
|
||||
## ⚡ Get started
|
||||
## ⚡ Get Started
|
||||
|
||||
### 1. Install Specify CLI
|
||||
|
||||
@@ -84,6 +84,8 @@ uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME
|
||||
|
||||
### 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.
|
||||
|
||||
```bash
|
||||
@@ -143,7 +145,7 @@ Want to see Spec Kit in action? Watch our [video overview](https://www.youtube.c
|
||||
| [Windsurf](https://windsurf.com/) | ✅ | |
|
||||
| [Kilo Code](https://github.com/Kilo-Org/kilocode) | ✅ | |
|
||||
| [Auggie CLI](https://docs.augmentcode.com/cli/overview) | ✅ | |
|
||||
| [CodeBuddy](https://www.codebuddy.ai/) | ✅ | |
|
||||
| [CodeBuddy CLI](https://www.codebuddy.ai/cli) | ✅ | |
|
||||
| [Roo Code](https://roocode.com/) | ✅ | |
|
||||
| [Codex CLI](https://github.com/openai/codex) | ✅ | |
|
||||
| [Amazon Q Developer CLI](https://aws.amazon.com/developer/learning/q-developer-cli/) | ⚠️ | Amazon Q Developer CLI [does not support](https://github.com/aws/amazon-q-developer-cli/issues/3064) custom arguments for slash commands. |
|
||||
@@ -247,7 +249,7 @@ Additional commands for enhanced quality and validation:
|
||||
|------------------|------------------------------------------------------------------------------------------------|
|
||||
| `SPECIFY_FEATURE` | Override feature detection for non-Git repositories. Set to the feature directory name (e.g., `001-photo-albums`) to work on a specific feature when not using Git branches.<br/>**Must be set in the context of the agent you're working with prior to using `/speckit.plan` or follow-up commands. |
|
||||
|
||||
## 📚 Core philosophy
|
||||
## 📚 Core Philosophy
|
||||
|
||||
Spec-Driven Development is a structured process that emphasizes:
|
||||
|
||||
@@ -256,7 +258,7 @@ Spec-Driven Development is a structured process that emphasizes:
|
||||
- **Multi-step refinement** rather than one-shot code generation from prompts
|
||||
- **Heavy reliance** on advanced AI model capabilities for specification interpretation
|
||||
|
||||
## 🌟 Development phases
|
||||
## 🌟 Development Phases
|
||||
|
||||
| Phase | Focus | Key Activities |
|
||||
|-------|-------|----------------|
|
||||
@@ -264,7 +266,7 @@ Spec-Driven Development is a structured process that emphasizes:
|
||||
| **Creative Exploration** | Parallel implementations | <ul><li>Explore diverse solutions</li><li>Support multiple technology stacks & architectures</li><li>Experiment with UX patterns</li></ul> |
|
||||
| **Iterative Enhancement** ("Brownfield") | Brownfield modernization | <ul><li>Add features iteratively</li><li>Modernize legacy systems</li><li>Adapt processes</li></ul> |
|
||||
|
||||
## 🎯 Experimental goals
|
||||
## 🎯 Experimental Goals
|
||||
|
||||
Our research and experimentation focus on:
|
||||
|
||||
@@ -300,14 +302,14 @@ Our research and experimentation focus on:
|
||||
|
||||
If you encounter issues with an agent, please open an issue so we can refine the integration.
|
||||
|
||||
## 📖 Learn more
|
||||
## 📖 Learn More
|
||||
|
||||
- **[Complete Spec-Driven Development Methodology](./spec-driven.md)** - Deep dive into the full process
|
||||
- **[Detailed Walkthrough](#-detailed-process)** - Step-by-step implementation guide
|
||||
|
||||
---
|
||||
|
||||
## 📋 Detailed process
|
||||
## 📋 Detailed Process
|
||||
|
||||
<details>
|
||||
<summary>Click to expand the detailed step-by-step walkthrough</summary>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Prerequisites
|
||||
|
||||
- **Linux/macOS** (or Windows; PowerShell scripts now supported without WSL)
|
||||
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), or [Gemini CLI](https://github.com/google-gemini/gemini-cli)
|
||||
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), [Codebuddy CLI](https://www.codebuddy.ai/cli) or [Gemini CLI](https://github.com/google-gemini/gemini-cli)
|
||||
- [uv](https://docs.astral.sh/uv/) for package management
|
||||
- [Python 3.11+](https://www.python.org/downloads/)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
@@ -34,6 +34,7 @@ You can proactively specify your AI agent during initialization:
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai claude
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai gemini
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai copilot
|
||||
uvx --from git+https://github.com/github/spec-kit.git specify init <project_name> --ai codebuddy
|
||||
```
|
||||
|
||||
### Specify Script Type (Shell vs PowerShell)
|
||||
|
||||
|
Before Width: | Height: | Size: 529 KiB After Width: | Height: | Size: 302 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 3.0 MiB After Width: | Height: | Size: 1.7 MiB |
@@ -19,21 +19,21 @@ get_current_branch() {
|
||||
echo "$SPECIFY_FEATURE"
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
# Then check git if available
|
||||
if git rev-parse --abbrev-ref HEAD >/dev/null 2>&1; then
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
# For non-git repos, try to find the latest feature directory
|
||||
local repo_root=$(get_repo_root)
|
||||
local specs_dir="$repo_root/specs"
|
||||
|
||||
|
||||
if [[ -d "$specs_dir" ]]; then
|
||||
local latest_feature=""
|
||||
local highest=0
|
||||
|
||||
|
||||
for dir in "$specs_dir"/*; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
local dirname=$(basename "$dir")
|
||||
@@ -47,13 +47,13 @@ get_current_branch() {
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
if [[ -n "$latest_feature" ]]; then
|
||||
echo "$latest_feature"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
echo "main" # Final fallback
|
||||
}
|
||||
|
||||
@@ -65,35 +65,77 @@ has_git() {
|
||||
check_feature_branch() {
|
||||
local branch="$1"
|
||||
local has_git_repo="$2"
|
||||
|
||||
|
||||
# For non-git repos, we can't enforce branch naming but still provide output
|
||||
if [[ "$has_git_repo" != "true" ]]; then
|
||||
echo "[specify] Warning: Git repository not detected; skipped branch validation" >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
if [[ ! "$branch" =~ ^[0-9]{3}- ]]; then
|
||||
echo "ERROR: Not on a feature branch. Current branch: $branch" >&2
|
||||
echo "Feature branches should be named like: 001-feature-name" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
get_feature_dir() { echo "$1/specs/$2"; }
|
||||
|
||||
# Find feature directory by numeric prefix instead of exact branch match
|
||||
# This allows multiple branches to work on the same spec (e.g., 004-fix-bug, 004-add-feature)
|
||||
find_feature_dir_by_prefix() {
|
||||
local repo_root="$1"
|
||||
local branch_name="$2"
|
||||
local specs_dir="$repo_root/specs"
|
||||
|
||||
# Extract numeric prefix from branch (e.g., "004" from "004-whatever")
|
||||
if [[ ! "$branch_name" =~ ^([0-9]{3})- ]]; then
|
||||
# If branch doesn't have numeric prefix, fall back to exact match
|
||||
echo "$specs_dir/$branch_name"
|
||||
return
|
||||
fi
|
||||
|
||||
local prefix="${BASH_REMATCH[1]}"
|
||||
|
||||
# Search for directories in specs/ that start with this prefix
|
||||
local matches=()
|
||||
if [[ -d "$specs_dir" ]]; then
|
||||
for dir in "$specs_dir"/"$prefix"-*; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
matches+=("$(basename "$dir")")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Handle results
|
||||
if [[ ${#matches[@]} -eq 0 ]]; then
|
||||
# No match found - return the branch name path (will fail later with clear error)
|
||||
echo "$specs_dir/$branch_name"
|
||||
elif [[ ${#matches[@]} -eq 1 ]]; then
|
||||
# Exactly one match - perfect!
|
||||
echo "$specs_dir/${matches[0]}"
|
||||
else
|
||||
# Multiple matches - this shouldn't happen with proper naming convention
|
||||
echo "ERROR: Multiple spec directories found with prefix '$prefix': ${matches[*]}" >&2
|
||||
echo "Please ensure only one spec directory exists per numeric prefix." >&2
|
||||
echo "$specs_dir/$branch_name" # Return something to avoid breaking the script
|
||||
fi
|
||||
}
|
||||
|
||||
get_feature_paths() {
|
||||
local repo_root=$(get_repo_root)
|
||||
local current_branch=$(get_current_branch)
|
||||
local has_git_repo="false"
|
||||
|
||||
|
||||
if has_git; then
|
||||
has_git_repo="true"
|
||||
fi
|
||||
|
||||
local feature_dir=$(get_feature_dir "$repo_root" "$current_branch")
|
||||
|
||||
|
||||
# Use prefix-based lookup to support multiple branches per spec
|
||||
local feature_dir=$(find_feature_dir_by_prefix "$repo_root" "$current_branch")
|
||||
|
||||
cat <<EOF
|
||||
REPO_ROOT='$repo_root'
|
||||
CURRENT_BRANCH='$current_branch'
|
||||
|
||||
@@ -250,7 +250,7 @@ get_commands_for_language() {
|
||||
echo "cargo test && cargo clippy"
|
||||
;;
|
||||
*"JavaScript"*|*"TypeScript"*)
|
||||
echo "npm test && npm run lint"
|
||||
echo "npm test \\&\\& npm run lint"
|
||||
;;
|
||||
*)
|
||||
echo "# Add commands for $lang"
|
||||
@@ -583,7 +583,7 @@ update_specific_agent() {
|
||||
update_agent_file "$ROO_FILE" "Roo Code"
|
||||
;;
|
||||
codebuddy)
|
||||
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy"
|
||||
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
|
||||
;;
|
||||
q)
|
||||
update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
|
||||
@@ -651,7 +651,7 @@ update_all_existing_agents() {
|
||||
fi
|
||||
|
||||
if [[ -f "$CODEBUDDY_FILE" ]]; then
|
||||
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy"
|
||||
update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
|
||||
found_agent=true
|
||||
fi
|
||||
|
||||
|
||||
@@ -378,7 +378,7 @@ function Update-SpecificAgent {
|
||||
'kilocode' { Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code' }
|
||||
'auggie' { Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI' }
|
||||
'roo' { Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code' }
|
||||
'codebuddy' { Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy' }
|
||||
'codebuddy' { Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI' }
|
||||
'q' { Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI' }
|
||||
default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|q'; return $false }
|
||||
}
|
||||
@@ -397,7 +397,7 @@ function Update-AllExistingAgents {
|
||||
if (Test-Path $KILOCODE_FILE) { if (-not (Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $AUGGIE_FILE) { if (-not (Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $ROO_FILE) { if (-not (Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $CODEBUDDY_FILE) { if (-not (Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $CODEBUDDY_FILE) { if (-not (Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $Q_FILE) { if (-not (Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI')) { $ok = $false }; $found = $true }
|
||||
if (-not $found) {
|
||||
Write-Info 'No existing agent files found, creating default Claude file...'
|
||||
|
||||
@@ -129,7 +129,7 @@ AGENT_CONFIG = {
|
||||
"codebuddy": {
|
||||
"name": "CodeBuddy",
|
||||
"folder": ".codebuddy/",
|
||||
"install_url": "https://www.codebuddy.ai",
|
||||
"install_url": "https://www.codebuddy.ai/cli",
|
||||
"requires_cli": True,
|
||||
},
|
||||
"roo": {
|
||||
@@ -485,6 +485,73 @@ def init_git_repo(project_path: Path, quiet: bool = False) -> Tuple[bool, Option
|
||||
finally:
|
||||
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]:
|
||||
repo_owner = "github"
|
||||
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)
|
||||
dest_file = dest_path / rel_path
|
||||
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:
|
||||
shutil.copytree(item, dest_path)
|
||||
else:
|
||||
|
||||
@@ -79,6 +79,12 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
- **Java**: `target/`, `*.class`, `*.jar`, `.gradle/`, `build/`
|
||||
- **C#/.NET**: `bin/`, `obj/`, `*.user`, `*.suo`, `packages/`
|
||||
- **Go**: `*.exe`, `*.test`, `vendor/`, `*.out`
|
||||
- **Ruby**: `.bundle/`, `log/`, `tmp/`, `*.gem`, `vendor/bundle/`
|
||||
- **PHP**: `vendor/`, `*.log`, `*.cache`, `*.env`
|
||||
- **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*`
|
||||
- **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*`
|
||||
- **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*`
|
||||
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `Makefile`, `config.log`, `.idea/`, `*.log`, `.env*`
|
||||
- **Universal**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/`
|
||||
|
||||
**Tool-Specific Patterns**:
|
||||
|
||||