mirror of
https://github.com/Xevion/dotfiles.git
synced 2026-01-31 02:24:11 -06:00
feat: add chezmoi merge tools with VSCode integration and Fish helper
- Add VSCode-based merge helper with clear visual layout explanation - Add Fish function for fzf-based interactive conflict selection - Update CLAUDE.md with .tmpl file search patterns and tool usage guidelines
This commit is contained in:
@@ -66,6 +66,28 @@ When working in this repository, you're reading both the global AGENTS.md (gener
|
|||||||
- `encrypted_*.age` age-encrypted files (safe to commit)
|
- `encrypted_*.age` age-encrypted files (safe to commit)
|
||||||
- `run_onchange_*` executable scripts that run during apply
|
- `run_onchange_*` executable scripts that run during apply
|
||||||
|
|
||||||
|
**Finding Files - Template Extension Patterns:**
|
||||||
|
|
||||||
|
⚠️ **CRITICAL**: Most managed files have `.tmpl` extensions. Use wildcard patterns to find both base and `.tmpl` variants in one search.
|
||||||
|
|
||||||
|
Common patterns where `.tmpl` is added to the FULL filename:
|
||||||
|
- `config.md` → `config.md.tmpl` (NOT `config.tmpl`)
|
||||||
|
- `settings.json` → `settings.json.tmpl` (NOT `settings.tmpl`)
|
||||||
|
- `config.ts` → `config.ts.tmpl` (NOT `config.tmpl`)
|
||||||
|
- `.bashrc` → `dot_bashrc.tmpl` (combines `dot_` and `.tmpl`)
|
||||||
|
- `.config/opencode/opencode.jsonc` → `dot_config/opencode/opencode.jsonc.tmpl`
|
||||||
|
|
||||||
|
**Search strategy - Use wildcards to catch both variants:**
|
||||||
|
- Pattern: `**/filename*` (e.g., `**/CLAUDE.md*` finds both `CLAUDE.md` AND `CLAUDE.md.tmpl`)
|
||||||
|
- Pattern: `**/*.ext.tmpl` for type-specific template files (e.g., `**/*.ts.tmpl`, `**/*.json.tmpl`)
|
||||||
|
- Check both `home/` and `home/.chezmoitemplates/` directories
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
- Looking for "CLAUDE.md"? → Search `**/CLAUDE.md*` (finds both base and `.tmpl`)
|
||||||
|
- Looking for "config.nu"? → Search `**/config.nu*` (finds both variants)
|
||||||
|
- Looking for all TypeScript templates? → Search `**/*.ts.tmpl`
|
||||||
|
- Looking for all JSON configs? → Search `**/*.json*` (finds `.json` and `.json.tmpl`)
|
||||||
|
|
||||||
**Template System:**
|
**Template System:**
|
||||||
- Uses Go templates with platform detection
|
- Uses Go templates with platform detection
|
||||||
- Two types of templates with different variable access patterns:
|
- Two types of templates with different variable access patterns:
|
||||||
|
|||||||
@@ -45,10 +45,11 @@
|
|||||||
encryption = "age"
|
encryption = "age"
|
||||||
|
|
||||||
[merge]
|
[merge]
|
||||||
command = "bash"
|
command = "chezmoi-merge-helper.sh"
|
||||||
args = [
|
args = [
|
||||||
"-c",
|
"{{ "{{" }} .Destination {{ "}}" }}",
|
||||||
"cp {{ "{{" }} .Target {{ "}}" }} {{ "{{" }} .Target {{ "}}" }}.base && code --new-window --wait --merge {{ "{{" }} .Destination {{ "}}" }} {{ "{{" }} .Target {{ "}}" }} {{ "{{" }} .Target {{ "}}" }}.base {{ "{{" }} .Source {{ "}}" }}",
|
"{{ "{{" }} .Target {{ "}}" }}",
|
||||||
|
"{{ "{{" }} .Source {{ "}}" }}",
|
||||||
]
|
]
|
||||||
|
|
||||||
[data]
|
[data]
|
||||||
|
|||||||
@@ -221,38 +221,88 @@ When a project uses `assert2`:
|
|||||||
- Grep tool for searching (not `grep`, `rg`)
|
- Grep tool for searching (not `grep`, `rg`)
|
||||||
- Bash ONLY for actual system commands and terminal operations
|
- Bash ONLY for actual system commands and terminal operations
|
||||||
|
|
||||||
### GitHub File Fetching
|
### GitHub & External Resources
|
||||||
|
|
||||||
When fetching files from GitHub repositories:
|
**Fetching file content from GitHub:**
|
||||||
|
|
||||||
- **STRONGLY prefer raw.githubusercontent.com over github.com**
|
- **STRONGLY prefer raw.githubusercontent.com over github.com**
|
||||||
- Raw URLs return plain content without HTML wrapper - simpler and faster
|
- Raw URLs return plain content without HTML wrapper - simpler and faster
|
||||||
- Pattern: `https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{path}`
|
- Pattern: `https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{path}`
|
||||||
- Example: `https://raw.githubusercontent.com/user/repo/main/src/file.rs`
|
- For specific commits/tags: `https://raw.githubusercontent.com/{owner}/{repo}/{commit-sha}/{path}`
|
||||||
- Only use github.com URLs when you need the web interface or rendered view
|
- Only use github.com URLs when you need the web interface or rendered view
|
||||||
|
|
||||||
- **Use GitHub CLI (`gh`) for repository operations**
|
**GitHub CLI (`gh`) for everything else:**
|
||||||
- Perfect for metadata and repository management
|
|
||||||
- Examples: `gh repo view`, `gh issue list`, `gh pr view`, `gh pr checkout`
|
|
||||||
- More reliable than web scraping for structured data
|
|
||||||
|
|
||||||
- **Use MCP gh_grep tool for code search** (see below)
|
- **Authenticated API access** - use `gh api` for direct GitHub API calls:
|
||||||
|
- `gh api repos/{owner}/{repo}/releases/latest` - get latest release info
|
||||||
|
- `gh api repos/{owner}/{repo}/contents/{path}` - get file metadata/content
|
||||||
|
- `gh api repos/{owner}/{repo}` - get repository details
|
||||||
|
- Supports GraphQL: `gh api graphql -f query='...'`
|
||||||
|
|
||||||
|
- **Search GitHub** - use `gh search` subcommands:
|
||||||
|
- `gh search repos "query"` - find repositories
|
||||||
|
- `gh search issues "query" --repo owner/repo` - search issues
|
||||||
|
- `gh search code "query"` - GitHub's native code search (different from gh_grep)
|
||||||
|
|
||||||
|
- **Repository operations** - metadata and management:
|
||||||
|
- `gh repo view owner/repo` - repository info
|
||||||
|
- `gh release list -R owner/repo` - list releases with versions
|
||||||
|
- `gh issue/pr view` - issue and PR details
|
||||||
|
|
||||||
### MCP Tools (When Available)
|
### MCP Tools (When Available)
|
||||||
|
|
||||||
**gh_grep (GitHub Code Search)**
|
**gh_grep - CRITICAL: THIS IS LITERAL PATTERN MATCHING, NOT SEMANTIC SEARCH**
|
||||||
- Search real-world code examples from 1M+ public repos
|
|
||||||
- Use for: unfamiliar APIs, usage patterns, real implementation examples
|
This tool searches for **exact character sequences** in source code files. It is `grep`, not Google.
|
||||||
- Search for **literal code**, not keywords: `'useState('`, `'async function'`, `'import React from'`
|
|
||||||
- Use regex with `useRegexp: true` for flexible patterns: `'(?s)useEffect\\(\\(\\) => {.*cleanup'`
|
It CANNOT:
|
||||||
- Filter by `language`, `repo`, or `path` to narrow results
|
- Understand what you're looking for conceptually
|
||||||
- Perfect for seeing how others solve similar problems
|
- Find "related" code or similar patterns
|
||||||
|
- Interpret natural language or keywords
|
||||||
|
|
||||||
|
❌ **WRONG** - these will fail or return garbage:
|
||||||
|
- `"how to handle errors"` → literally searches for that sentence in code
|
||||||
|
- `"authentication"` → only finds that exact word as a string, not auth implementations
|
||||||
|
- `"best practices"` → completely useless
|
||||||
|
- `"react state management"` → meaningless as a code pattern
|
||||||
|
|
||||||
|
✅ **CORRECT** - search for actual code that appears in source files:
|
||||||
|
- `'useAuth('` → finds useAuth function calls
|
||||||
|
- `'catch (AuthError'` → finds specific error handling
|
||||||
|
- `'implements OAuth'` → finds class implementations
|
||||||
|
- `'(?s)async function.*await fetch'` with `useRegexp: true` → async functions with fetch
|
||||||
|
|
||||||
|
**Rule of thumb**: If your query wouldn't make sense copy-pasted into a source file, it's wrong.
|
||||||
|
|
||||||
|
Use `language`, `repo`, and `path` filters to narrow results.
|
||||||
|
|
||||||
**context7 (Library Documentation)**
|
**context7 (Library Documentation)**
|
||||||
- Get up-to-date docs for libraries/frameworks
|
- Get up-to-date docs for libraries/frameworks
|
||||||
- Two-step process: `resolve-library-id` → `get-library-docs`
|
- Two-step process: `resolve-library-id` → `query-docs`
|
||||||
- Use `mode: 'code'` for API references (default), `mode: 'info'` for guides
|
- Prefer when you need official documentation vs community examples from gh_grep
|
||||||
- Prefer when you need official docs vs community examples
|
|
||||||
|
## Useful CLI Tools
|
||||||
|
|
||||||
|
Prefer these over convoluted bash pipelines or manual parsing.
|
||||||
|
|
||||||
|
**JSON Processing (`jq`):**
|
||||||
|
- Use for parsing API responses, transforming configs, extracting data
|
||||||
|
- Example: `gh api repos/owner/repo/releases | jq '.[0] | {tag: .tag_name, date: .published_at}'`
|
||||||
|
- Pipe any JSON output through jq for readable formatting: `... | jq .`
|
||||||
|
|
||||||
|
**Quick TypeScript Scripts (`bun`):**
|
||||||
|
- When shell gets too complex, write a quick inline script instead
|
||||||
|
- Prefer over chained `sed`/`awk`/`grep` pipelines for data transformation
|
||||||
|
- Example: `bun -e "console.log(JSON.parse(require('fs').readFileSync('data.json')).items.filter(x => x.active).length)"`
|
||||||
|
- Can also run `.ts` files directly: `bun run script.ts`
|
||||||
|
|
||||||
|
**Benchmarking (`hyperfine`):**
|
||||||
|
- Compare command performance: `hyperfine 'command1' 'command2'`
|
||||||
|
- Useful for verifying optimization claims
|
||||||
|
|
||||||
|
**Codebase Statistics (`tokei`):**
|
||||||
|
- Quick language breakdown and LOC counts: `tokei .`
|
||||||
|
- Useful for understanding unfamiliar codebases
|
||||||
|
|
||||||
## Security & Error Handling
|
## Security & Error Handling
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
function chmerge --description "Interactively merge chezmoi conflicts using fzf"
|
||||||
|
# Get files with merge conflicts (MM = modified in both source and target)
|
||||||
|
set -l conflict_files (chezmoi status | grep '^MM ' | awk '{print $2}')
|
||||||
|
|
||||||
|
if test (count $conflict_files) -eq 0
|
||||||
|
echo "No merge conflicts found."
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# Use fzf for selection with multi-select enabled
|
||||||
|
set -l selected (printf '%s\n' $conflict_files | fzf \
|
||||||
|
--multi \
|
||||||
|
--preview 'chezmoi diff {}' \
|
||||||
|
--preview-window 'right:70%:wrap' \
|
||||||
|
--header 'Select files to merge (Tab for multi-select, Enter to confirm)' \
|
||||||
|
--bind 'ctrl-/:toggle-preview')
|
||||||
|
|
||||||
|
if test (count $selected) -eq 0
|
||||||
|
echo "No files selected."
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# Convert to absolute target paths and merge
|
||||||
|
for file in $selected
|
||||||
|
# Expand ~ to home directory for chezmoi merge
|
||||||
|
set -l target_path (string replace -r '^~' $HOME $file)
|
||||||
|
echo "Merging: $file"
|
||||||
|
chezmoi merge $target_path
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Helper script for chezmoi merge with clear labels
|
||||||
|
# Arguments: $1=destination $2=target $3=source
|
||||||
|
|
||||||
|
destination="$1"
|
||||||
|
target="$2"
|
||||||
|
source="$3"
|
||||||
|
|
||||||
|
# Create base file (copy of target state)
|
||||||
|
base="${target}.base"
|
||||||
|
cp "$target" "$base"
|
||||||
|
|
||||||
|
# Show clear explanation before merge
|
||||||
|
cat << EOF
|
||||||
|
╔════════════════════════════════════════════════════════════════╗
|
||||||
|
║ CHEZMOI MERGE LAYOUT ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ ║
|
||||||
|
║ LEFT (Current): DESTINATION - File in your home dir ║
|
||||||
|
║ ↓ External changes (e.g., app updates) ║
|
||||||
|
║ ║
|
||||||
|
║ RIGHT (Incoming): TARGET - What chezmoi wants to apply ║
|
||||||
|
║ ↓ Your chezmoi changes (templates, etc) ║
|
||||||
|
║ ║
|
||||||
|
║ BOTTOM (Result): SOURCE - Will be saved to chezmoi repo ║
|
||||||
|
║ ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ File: $(basename "$destination")
|
||||||
|
╚════════════════════════════════════════════════════════════════╝
|
||||||
|
|
||||||
|
Press Enter to open merge editor...
|
||||||
|
EOF
|
||||||
|
|
||||||
|
read -r
|
||||||
|
|
||||||
|
# Launch VSCode merge
|
||||||
|
# Syntax: code --merge <current> <incoming> <base> <result>
|
||||||
|
code --new-window --wait --merge "$destination" "$target" "$base" "$source"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
rm -f "$base"
|
||||||
Reference in New Issue
Block a user