add-pattern
Add a new conflict-resolution pattern to GitWand core. Use this skill whenever someone wants to add a pattern, resolution rule, new conflict case, new…
Use this skill when the user wants to expose a Rust feature to the Vue frontend, add a Tauri IPC command, invoke something from a Vue component, or wire up any backend/frontend communication via Tauri's invoke bridge.
$ npx -y skills add devlint/GitWand --skill add-tauri-command --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/add-tauri-commandContext preview
The summary Claude sees to decide when to auto-load this skill.
Use this skill when the user wants to expose a Rust feature to the Vue frontend, add a Tauri IPC command, invoke something from a Vue component, or wire up any backend/frontend communication via Tauri's invoke bridge.
name: add-tauri-command description: "Use this skill when the user wants to expose a Rust feature to the Vue frontend, add a Tauri IPC command, invoke something from a Vue component, or wire up any backend/frontend communication via Tauri's invoke bridge."
Ajouter une commande Tauri de bout en bout — Rust + TypeScript dans le même commit, sans trou de sécurité.
Les deux fichiers cibles sont toujours :
Les composants et composables Vue ne doivent **jamais** appeler `invoke()` directement. Tout passe par `backend.ts`.
---
Avant d'écrire une ligne de code, répondre à ces questions :
| Question | Impact | |---|---| | Nom de la commande ? | snake_case en Rust, camelCase en TS | | Paramètres et leurs types ? | Identifier ceux qui sont des chemins → `safe_repo_path` obligatoire | | Type de retour ? | Définir / réutiliser une interface TS dans `types.ts` | | Spawne-t-elle un process externe ? | Vérifier les capabilities Tauri | | Exécute-t-elle `git` ? | Règle `.arg()` obligatoire, jamais `format!()` |
---
Appliquer les règles dans cet ordre exact :
/// Retourne le contenu du fichier de config d'un repo.
#[tauri::command]
fn read_config_file(cwd: String, path: String) -> Result<String, String> {
// ✅ TOUJOURS : valider le chemin avant tout usage
let safe = safe_repo_path(&cwd, &path)
.map_err(|e| e.to_string())?;
let content = std::fs::read_to_string(&safe)
.map_err(|e| e.to_string())?;
Ok(content)
}// ❌ JAMAIS : path traversal possible
fn read_config_file(cwd: String, path: String) -> Result<String, String> {
let full = std::path::PathBuf::from(&cwd).join(&path); // "../../../etc/passwd" passe !
Ok(std::fs::read_to_string(full).map_err(|e| e.to_string())?)
}// ✅ Chaque argument est isolé : pas d'injection possible
let output = Command::new(git_binary())
.arg("log")
.arg("--oneline")
.arg("-n").arg(&limit.to_string())
.arg("--").arg(&safe_path)
.current_dir(&cwd)
.output()
.map_err(|e| e.to_string())?;// ❌ JAMAIS : une valeur contrôlée par le frontend dans une chaîne shell
Command::new("sh").arg("-c")
.arg(format!("git log -- {}", user_path)) // injection garantie/// Retourne les N derniers commits du fichier `path` dans le repo `cwd`.
/// Erreur si le chemin sort du repo ou si git échoue.
#[tauri::command]
fn file_log(cwd: String, path: String, limit: u32) -> Result<Vec<String>, String> {
let safe = safe_repo_path(&cwd, &path).map_err(|e| e.to_string())?;
// ...
Ok(lines)
}---
Dans `run()`, ajouter le nom de la fonction (snake_case) dans `.invoke_handler(...)` :
.invoke_handler(tauri::generate_handler![
// commandes existantes…
get_conflicted_files,
read_file,
write_file,
// ✅ nouvelle commande
file_log,
])Oublier cette étape → Tauri retourne `command not found` à l'exécution, sans erreur de compilation.
---
Respecter le pattern existant : async function typée, `tauriInvoke()` en mode Tauri, fallback dev-server en mode browser.
/**
* Retourne les N derniers commits du fichier `path` dans le repo `cwd`.
*/
export async function fileLog(
cwd: string,
path: string,
limit: number = 50,
): Promise<string[]> {
if (isTauri()) {
return tauriInvoke<string[]>('file_log', { cwd, path, limit })
}
const res = await fetch(`${DEV_SERVER}/api/file-log`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cwd, path, limit }),
})
if (!res.ok) throw new Error(`Dev server error: ${res.status}`)
return res.json()
}Points de contrôle :
---
Les commandes git standard n'ont pas besoin de nouvelles capabilities.
Si la commande **spawne un process externe** (autre que `git`) ou **accède à des fichiers hors du repo** :
1. Ouvrir `apps/desktop/src-tauri/capabilities/default.json` 2. Ajouter la permission minimale nécessaire — exemple pour un process externe :
{
"permissions": [
"shell:allow-execute",
{ "identifier": "shell:allow-spawn", "allow": [{ "name": "gh" }] }
]
}Ne jamais utiliser `shell:allow-execute` de façon globale (autoriserait n'importe quel binaire). Toujours restreindre au nom exact de l'exécutable.
---
# Compile le frontend et vérifie les types TypeScript cd apps/desktop && pnpm dev:web # Vérifie la compilation Rust sans lancer l'app cd apps/desktop/src-tauri && cargo check
Les deux doivent passer sans erreur avant de commiter. Rust + TypeScript partent dans le **même commit** — un wrapper TS pointant vers une commande Rust non enregistrée est une bombe à retardement.
---
The Git client that actually resolves conflicts: 8 deterministic patterns auto-resolve the ones that were never decisions, full trace on the rest. Native (Tauri 2 + Rust), free, MIT.
Repo: devlint/GitWand
Add a new conflict-resolution pattern to GitWand core. Use this skill whenever someone wants to add a pattern, resolution rule, new conflict case, new…
Add a format-specific resolver to GitWand core. Use this skill whenever someone wants to add support for a new file format, file extension, lockfile, config…
Synchronise les fichiers de locale GitWand. Se déclencher dès que l'utilisateur parle d'ajouter une string UI, d'un texte dans l'interface,…
Guide a clean GitWand release end-to-end: bump version, update CHANGELOG, commit, tag, and push. Trigger on: make a release, bump version, publish to npm, ship…