diff --git a/.claude/commands/sysinfo.md b/.claude/commands/sysinfo.md deleted file mode 100644 index 780f0e8..0000000 --- a/.claude/commands/sysinfo.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -description: Affiche les informations système et du projet ---- - -# Informations système - -## Utilisateur et dossier -Utilisateur : !whoami -Dossier actuel : !pwd - -## Fichiers du projet -!`ls -1 | head -10` - -## État Git (si dépôt) -!`git status --short 2>/dev/null || echo "Pas un dépôt Git"` - -## Statistiques TypeScript -!`find packages -name "*.ts" | wc -l` fichiers TypeScript trouvés - -Analyse ces informations et donne un résumé du projet. diff --git a/CHANGELOG_SHELL_COMMANDS.md b/CHANGELOG_SHELL_COMMANDS.md deleted file mode 100644 index 07080d4..0000000 --- a/CHANGELOG_SHELL_COMMANDS.md +++ /dev/null @@ -1,107 +0,0 @@ -# Changelog - Commande Shell `!` - -## Version actuelle - -### Nouvelle fonctionnalité : Commande Shell `!` - -**Date** : Décembre 2024 - -#### Description - -Implémentation de la commande `!` permettant d'exécuter des commandes shell directement dans les prompts et les commandes markdown personnalisées. - -#### Syntaxe - -- **Commande simple** : `!commande` - exécute la commande et remplace par sa sortie -- **Commande avec arguments** : `!`commande avec args`` - utilise des backticks pour les espaces - -#### Fonctionnalités - -1. **Exécution inline dans les prompts** - - L'utilisateur peut taper : `Analyse le projet : !`git status`` - - MagicCode exécute la commande et envoie le résultat au LLM - -2. **Support dans les commandes markdown** - - Les fichiers `.claude/commands/**/*.md` peuvent contenir des commandes `!` - - Expansion automatique avec les arguments `$1`, `$2`, etc. - -3. **Gestion intelligente** - - Exécution parallèle de multiples commandes pour performance - - Timeout de 30 secondes par commande - - Buffer de sortie limité à 10 MB - - Gestion des erreurs avec messages clairs - -4. **Intégration avec les permissions** - - Respect des variables d'environnement de `.claude/settings.json` - - Exécution dans le dossier de travail configuré - -#### Fichiers modifiés/créés - -- ✨ **Nouveau** : `packages/ext-claudecode/src/shell-commands.ts` - Logique d'exécution -- ✨ **Nouveau** : `packages/ext-claudecode/src/shell-commands.test.ts` - Tests unitaires (11 tests) -- ✨ **Nouveau** : `packages/ext-claudecode/SHELL_COMMANDS.md` - Documentation détaillée -- ✨ **Nouveau** : `.claude/commands/sysinfo.md` - Exemple de commande -- 🔧 **Modifié** : `packages/cli/src/index.ts` - Intégration dans la boucle principale -- 🔧 **Modifié** : `packages/ext-claudecode/src/commands.ts` - Support asynchrone -- 🔧 **Modifié** : `packages/ext-claudecode/src/mode.ts` - Passage des options -- 🔧 **Modifié** : `packages/ext-claudecode/src/index.ts` - Export des fonctions -- 🔧 **Modifié** : `packages/core/src/types.ts` - SlashCommand async -- 🔧 **Modifié** : `README.md` - Documentation principale - -#### Tests - -- ✅ 11 tests unitaires pour `shell-commands` -- ✅ Tests d'intégration dans `lot2.test.ts` mis à jour -- ✅ Tous les tests passent (84/84) -- ✅ TypeCheck OK sur tous les packages - -#### Exemple d'utilisation - -**Dans un prompt direct** : -``` -Utilisateur actuel : !whoami -Liste des fichiers : !`ls -la` -``` - -**Dans `.claude/commands/status.md`** : -```markdown ---- -description: État du projet ---- - -## Git -!`git status --short` - -## Derniers commits -!`git log --oneline -5` -``` - -Puis utiliser `/status` dans MagicCode. - -#### Impact sur l'API - -- ⚠️ **Breaking change mineur** : `SlashCommand.prompt()` retourne maintenant `string | Promise` - - Rétrocompatible : les commandes synchrones fonctionnent toujours - - Les appels doivent maintenant être `await`és - -#### Notes techniques - -- Utilise `child_process.exec` pour l'exécution -- Regex de détection : `/!((?:`[^`]+`)|(?:[^\s]+))/g` -- Expansion de la fin vers le début pour éviter les décalages d'indices -- Protection TypeScript stricte avec vérifications nullables - -#### Documentation - -- Guide utilisateur complet dans `SHELL_COMMANDS.md` -- README mis à jour avec section dédiée -- Aide CLI mise à jour (`--help`) -- Commentaires de code détaillés - -#### Prochaines étapes possibles - -- [ ] Support des permissions plus fines pour les commandes `!` -- [ ] Sandbox optionnel avec restrictions -- [ ] Cache des résultats pour commandes identiques -- [ ] Support du streaming pour les commandes longues -- [ ] Interface de confirmation configurable diff --git a/COMMIT_MESSAGE.md b/COMMIT_MESSAGE.md deleted file mode 100644 index eba3885..0000000 --- a/COMMIT_MESSAGE.md +++ /dev/null @@ -1,82 +0,0 @@ -# Commit Message - Implémentation de la commande shell `!` - -## 🎯 Feature: Ajout de la commande shell `!` dans ClaudeCode - -### Description -Implémentation complète de la fonctionnalité permettant d'exécuter des commandes shell directement dans les prompts et les commandes markdown via la syntaxe `!`. - -### Fonctionnalités ajoutées -- Exécution de commandes shell inline avec `!commande` ou `!`commande args`` -- Support dans les prompts directs de l'utilisateur -- Support dans les fichiers `.claude/commands/**/*.md` -- Exécution parallèle de multiples commandes -- Gestion robuste des erreurs et timeouts -- Intégration avec les variables d'environnement de settings.json - -### Changements techniques - -#### Nouveaux fichiers -- `packages/ext-claudecode/src/shell-commands.ts` - Module principal -- `packages/ext-claudecode/src/shell-commands.test.ts` - Tests (11 tests) -- `packages/ext-claudecode/SHELL_COMMANDS.md` - Documentation utilisateur -- `.claude/commands/sysinfo.md` - Exemple de commande - -#### Modifications -- `packages/core/src/types.ts` - SlashCommand.prompt() async -- `packages/cli/src/index.ts` - Intégration de l'expansion shell -- `packages/ext-claudecode/src/commands.ts` - Support async avec renderCommandAsync() -- `packages/ext-claudecode/src/mode.ts` - Passage des options cwd/env -- `packages/ext-claudecode/src/index.ts` - Exports des fonctions shell -- `packages/ext-claudecode/src/lot2.test.ts` - Test async - -### Tests -- ✅ 11 nouveaux tests unitaires (100% passing) -- ✅ Tous les tests existants passent (84/84) -- ✅ TypeCheck OK sur tous les packages -- ✅ Build réussi - -### Breaking Changes -**Mineur** : `SlashCommand.prompt()` retourne maintenant `string | Promise` -- Impact minimal : rétrocompatible avec les commandes synchrones -- Migration : ajouter `await` pour les appels de `command.prompt()` - -### Documentation -- Guide utilisateur complet dans SHELL_COMMANDS.md -- README.md mis à jour avec nouvelle section -- 7 fichiers de documentation technique créés -- Aide CLI mise à jour - -### Exemples d'utilisation - -``` -# Prompt direct -Utilisateur actuel : !whoami -Fichiers du projet : !`ls -la` - -# Commande personnalisée (.claude/commands/status.md) -État Git : !`git status --short` -Derniers commits : !`git log --oneline -5` - -# Utilisation -/status -``` - -### Sécurité -- Timeout 30s par commande -- Buffer limité à 10 MB -- Gestion d'erreurs complète -- Variables d'environnement contrôlées -- Note : Exécution dans shell système (pas de sandbox complet) - -### Références -- Issue: Implémentation de la commande `!` (lot 2+) -- Documentation: README_IMPLEMENTATION.md pour index complet -- Tests: TEST_SHELL_COMMANDS.md pour validation manuelle - ---- - -**Type**: feature -**Scope**: ext-claudecode -**Status**: ✅ Prêt pour production - -Co-authored-by: MagicCode AI Assistant diff --git a/FILES_CHANGES.md b/FILES_CHANGES.md deleted file mode 100644 index 40df1dc..0000000 --- a/FILES_CHANGES.md +++ /dev/null @@ -1,157 +0,0 @@ -# Commande Shell `!` - Liste complète des modifications - -## 📁 Nouveaux fichiers créés - -### Code source -1. **`packages/ext-claudecode/src/shell-commands.ts`** (118 lignes) - - Logique principale d'exécution des commandes shell - - 3 fonctions exportées : `findShellCommands`, `executeShellCommand`, `expandShellCommands` - - Gestion timeout, buffer, erreurs - -2. **`packages/ext-claudecode/src/shell-commands.test.ts`** (83 lignes) - - 11 tests unitaires (2 suites) - - Coverage : détection, expansion, erreurs, env - -### Documentation -3. **`packages/ext-claudecode/SHELL_COMMANDS.md`** (3422 octets) - - Guide utilisateur complet - - Syntaxe, exemples, cas d'usage - - Permissions et limitations - -4. **`.claude/commands/sysinfo.md`** (440 octets) - - Exemple de commande utilisant `!` - - Démo fonctionnelle - -5. **`CHANGELOG_SHELL_COMMANDS.md`** (3589 octets) - - Historique détaillé de l'implémentation - - Impact API, tests, notes techniques - -6. **`IMPLEMENTATION_SUMMARY.md`** (3592 octets) - - Résumé exécutif - - Statut, fonctionnalités, exemples - -## 📝 Fichiers modifiés - -### Core -1. **`packages/core/src/types.ts`** - - Ligne 100 : `prompt(args: string): string | Promise;` - - Breaking change mineur pour support async - -### CLI -2. **`packages/cli/src/index.ts`** - - Import : ajout de `expandShellCommands, findShellCommands` - - Ligne 20-29 : HELP mis à jour avec mention commandes shell - - Ligne 230-246 : Logique d'expansion des commandes `!` avant envoi au LLM - - Ligne 226 : `await custom.prompt(args)` (async) - -### Extension ClaudeCode -3. **`packages/ext-claudecode/src/index.ts`** - - Export des utilitaires shell : `expandShellCommands, findShellCommands, executeShellCommand` - -4. **`packages/ext-claudecode/src/commands.ts`** - - Import : `expandShellCommands` - - Nouvelle fonction : `renderCommandAsync()` (lignes 39-50) - - `loadCommands()` : signature avec options, appel async (lignes 54-86) - -5. **`packages/ext-claudecode/src/mode.ts`** - - Ligne 41 : `loadCommands(dirs, { cwd: ctx.cwd, env: {} })` - -### Tests -6. **`packages/ext-claudecode/src/lot2.test.ts`** - - Ligne 121 : `await review?.prompt("a.ts")` (async) - -### Documentation racine -7. **`README.md`** - - Section "Extension ClaudeCode" enrichie (lignes 95-108) - - Sous-section "Commandes shell `!`" ajoutée - - Note de statut mise à jour (ligne 124) - -## 📊 Statistiques - -### Code -- **Nouveau code** : ~350 lignes -- **Tests** : 11 tests (100% passing) -- **Fichiers TS créés** : 2 -- **Fichiers TS modifiés** : 6 - -### Documentation -- **Nouveaux docs** : 4 fichiers markdown -- **Docs modifiés** : 1 (README) -- **Total documentation** : ~11 000 caractères - -### Qualité -- ✅ TypeCheck : 0 erreur -- ✅ Tests : 84/84 passing -- ✅ Build : Success -- ✅ Linting : Conforme - -## 🔄 Workflow d'utilisation - -### 1. Prompt direct -``` -Entrée utilisateur → Détection `!` → Exécution shell → Expansion → LLM -``` - -### 2. Commande markdown -``` -/commande → Lecture .md → Expansion args ($1...) → Expansion shell (!) → LLM -``` - -## 🎯 Points d'entrée - -### Pour les utilisateurs -- **CLI** : Taper directement `!commande` dans un prompt -- **Commandes** : Inclure `!`...`` dans `.claude/commands/*.md` - -### Pour les développeurs -```typescript -import { expandShellCommands } from '@magiccode/ext-claudecode'; - -const { expanded, executed } = await expandShellCommands( - "User: !whoami", - { cwd: process.cwd() } -); -``` - -## 🔐 Sécurité - -- ⚠️ Exécution dans le shell système (pas de sandbox) -- ✅ Timeout 30s par commande -- ✅ Buffer limité 10 MB -- ✅ Respect des variables d'environnement settings.json -- ✅ Gestion d'erreurs avec messages clairs -- ℹ️ Les permissions Bash existantes s'appliquent - -## 📋 Checklist de validation - -- [x] Code écrit et documenté -- [x] Tests unitaires (11/11 passing) -- [x] Tests d'intégration mis à jour -- [x] TypeCheck OK -- [x] Build OK -- [x] Documentation utilisateur complète -- [x] Exemple fonctionnel créé -- [x] README mis à jour -- [x] Changelog rédigé -- [x] Pas de régression (84/84 tests) - -## 🚀 Déploiement - -Prêt pour : -- ✅ Commit -- ✅ Merge -- ✅ Release -- ✅ Production - -Commande de test rapide : -```bash -cd magiccode -pnpm typecheck && pnpm test && pnpm build -``` - -## 📞 Support - -Documentation complète disponible dans : -- `packages/ext-claudecode/SHELL_COMMANDS.md` (guide utilisateur) -- `IMPLEMENTATION_SUMMARY.md` (vue technique) -- `CHANGELOG_SHELL_COMMANDS.md` (historique) diff --git a/IMPLEMENTATION_COMPLETE.md b/IMPLEMENTATION_COMPLETE.md deleted file mode 100644 index fabb5ad..0000000 --- a/IMPLEMENTATION_COMPLETE.md +++ /dev/null @@ -1,234 +0,0 @@ -# ✅ Implémentation complète de la commande `!` dans MagicCode - -## 🎯 Mission accomplie - -L'implémentation de la commande shell `!` dans l'extension ClaudeCode de MagicCode est **terminée, testée et validée**. - ---- - -## 📦 Livrables - -### Code source (2 fichiers) -- ✅ `packages/ext-claudecode/src/shell-commands.ts` - Module principal (118 lignes) -- ✅ `packages/ext-claudecode/src/shell-commands.test.ts` - Tests (83 lignes, 11 tests) - -### Documentation (4 fichiers) -- ✅ `packages/ext-claudecode/SHELL_COMMANDS.md` - Guide utilisateur complet -- ✅ `CHANGELOG_SHELL_COMMANDS.md` - Historique détaillé -- ✅ `IMPLEMENTATION_SUMMARY.md` - Résumé technique -- ✅ `FILES_CHANGES.md` - Liste exhaustive des changements - -### Exemples (1 fichier) -- ✅ `.claude/commands/sysinfo.md` - Commande de démonstration - -### Modifications (6 fichiers) -- ✅ `packages/core/src/types.ts` - Type SlashCommand async -- ✅ `packages/cli/src/index.ts` - Intégration CLI -- ✅ `packages/ext-claudecode/src/index.ts` - Exports -- ✅ `packages/ext-claudecode/src/commands.ts` - Support async -- ✅ `packages/ext-claudecode/src/mode.ts` - Options -- ✅ `packages/ext-claudecode/src/lot2.test.ts` - Test async - -### Documentation générale (1 fichier) -- ✅ `README.md` - Section ajoutée - ---- - -## ✨ Fonctionnalités implémentées - -### 1. Syntaxe simple et intuitive -``` -!commande → Exécute "commande" -!`commande args` → Exécute "commande args" -``` - -### 2. Utilisation dans les prompts directs -``` -Utilisateur: !whoami -Dossier: !pwd -Fichiers: !`ls -la` -``` -→ MagicCode exécute et remplace par les résultats avant d'envoyer au LLM - -### 3. Utilisation dans les commandes markdown -`.claude/commands/status.md` : -```markdown ---- -description: État du projet ---- - -Git: !`git status --short` -Commits: !`git log --oneline -5` -``` -→ Utilisez `/status` dans MagicCode - -### 4. Combinaison avec les arguments -```markdown -Info sur $1 : -!`git log $1 --oneline -10` -``` - ---- - -## ✅ Validation complète - -### Tests unitaires -``` -✅ 11/11 tests passing - - Détection de commandes - - Expansion avec remplacement - - Gestion des erreurs - - Variables d'environnement -``` - -### Qualité du code -``` -✅ TypeCheck: 5/5 packages OK -✅ Build: Success -✅ Tests d'intégration: 84/84 passing -✅ Pas de régression -``` - -### Résultat final -```bash -$ pnpm typecheck -packages/core typecheck: Done -packages/providers typecheck: Done -packages/ext-claudecode typecheck: Done -packages/ui typecheck: Done -packages/cli typecheck: Done - -$ pnpm test -Test Files 12 passed (12) -Tests 84 passed (84) - -$ pnpm build -ESM ⚡️ Build success in 25ms -``` - ---- - -## 🚀 Comment utiliser - -### Méthode 1 : Prompt direct -```bash -pnpm dev - -# Dans MagicCode, taper: -Analyse le projet dans !pwd avec !`ls -la | wc -l` fichiers -``` - -### Méthode 2 : Commande personnalisée -```bash -# Créer .claude/commands/info.md avec du contenu !... -# Puis dans MagicCode: -/info -``` - -### Méthode 3 : Commande intégrée (exemple fourni) -```bash -pnpm dev - -# Dans MagicCode: -/sysinfo -``` - ---- - -## 📊 Statistiques finales - -| Métrique | Valeur | -|----------|--------| -| Fichiers créés | 7 | -| Fichiers modifiés | 7 | -| Lignes de code | ~350 | -| Tests unitaires | 11 | -| Coverage | 100% | -| Documentation | ~15 Ko | -| Temps d'implémentation | ~2h | - ---- - -## 🔐 Sécurité et limitations - -### Sécurité -- ✅ Timeout 30s par commande -- ✅ Buffer max 10 MB -- ✅ Variables d'environnement contrôlées -- ✅ Gestion d'erreurs robuste -- ⚠️ Pas de sandbox (exécution système) - -### Limitations connues -- Pas de support pour commandes interactives -- Exécution dans le shell système (risques si commandes non contrôlées) -- Les permissions Bash existantes s'appliquent - ---- - -## 📚 Documentation disponible - -### Pour les utilisateurs -📖 **`packages/ext-claudecode/SHELL_COMMANDS.md`** -- Syntaxe complète -- Exemples pratiques -- Cas d'usage -- Gestion des erreurs - -### Pour les développeurs -📖 **`IMPLEMENTATION_SUMMARY.md`** -- Architecture technique -- API -- Points d'intégration - -### Pour la maintenance -📖 **`CHANGELOG_SHELL_COMMANDS.md`** -- Historique des changements -- Breaking changes -- Notes techniques - -📖 **`FILES_CHANGES.md`** -- Liste exhaustive des fichiers -- Modifications détaillées -- Statistiques - ---- - -## 🎉 Prêt pour la production - -✅ **Tous les critères sont remplis :** -- [x] Code implémenté et testé -- [x] Documentation complète -- [x] Exemples fonctionnels -- [x] Tests passent (100%) -- [x] TypeCheck OK -- [x] Build OK -- [x] Pas de régression -- [x] README mis à jour - ---- - -## 🔄 Prochaines étapes (optionnel) - -### Améliorations possibles -1. Sandbox optionnel pour sécurité renforcée -2. Cache des résultats pour commandes identiques -3. Streaming pour commandes longues -4. Permissions spécifiques pour `!` -5. Interface de confirmation configurable - -### Fonctionnalités supplémentaires à implémenter -- [ ] `allowed-tools` dans les commandes -- [ ] `model` dans les commandes -- [ ] `@fichier` pour inclure des fichiers - ---- - -## 👏 Conclusion - -L'implémentation de la commande `!` est **complète, robuste et prête à l'emploi**. Elle respecte l'architecture de MagicCode, est bien testée et documentée, et apporte une fonctionnalité puissante aux utilisateurs. - -**Status : ✅ PRÊT POUR PRODUCTION** - ---- - -*Document généré le 12/10/2024 - MagicCode Shell Commands Implementation* diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index febdecc..0000000 --- a/IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,142 +0,0 @@ -# Implémentation de la commande `!` - Résumé - -## ✅ Statut : Implémentation terminée - -L'implémentation de la commande shell `!` dans l'extension ClaudeCode est complète et fonctionnelle. - -## 📦 Ce qui a été fait - -### 1. Module principal (`shell-commands.ts`) -- ✅ Fonction `findShellCommands()` : détection des commandes `!` avec regex -- ✅ Fonction `executeShellCommand()` : exécution via child_process -- ✅ Fonction `expandShellCommands()` : remplacement et exécution parallèle -- ✅ Support des deux syntaxes : `!commande` et `!`commande avec args`` - -### 2. Tests (`shell-commands.test.ts`) -- ✅ 11 tests unitaires couvrant : - - Détection de commandes simples et complexes - - Expansion avec remplacement - - Gestion des erreurs - - Variables d'environnement -- ✅ Tous les tests passent - -### 3. Intégration CLI -- ✅ Import dans `packages/cli/src/index.ts` -- ✅ Détection et expansion avant envoi au LLM -- ✅ Affichage des résultats à l'utilisateur -- ✅ Gestion des erreurs avec messages clairs - -### 4. Support dans les commandes markdown -- ✅ Fonction `renderCommandAsync()` ajoutée -- ✅ `loadCommands()` mis à jour pour passer les options -- ✅ Mode mis à jour pour transmettre `cwd` et `env` -- ✅ Type `SlashCommand.prompt()` maintenant asynchrone - -### 5. Documentation -- ✅ `SHELL_COMMANDS.md` : guide utilisateur complet -- ✅ README.md mis à jour -- ✅ Aide CLI mise à jour -- ✅ Exemple de commande `.claude/commands/sysinfo.md` -- ✅ Changelog détaillé - -### 6. Qualité du code -- ✅ TypeCheck OK (100%) -- ✅ Tests OK (84/84) -- ✅ Build OK -- ✅ Protection TypeScript stricte -- ✅ Gestion d'erreurs robuste - -## 🎯 Fonctionnalités - -### Utilisateur peut : -1. **Taper directement** : `Liste des fichiers : !`ls -la`` -2. **Dans commandes custom** : Inclure `!`git status`` dans `.claude/commands/status.md` -3. **Combiner avec args** : `$1` + `!`...`` dans les commandes -4. **Voir les résultats** : Affichage avant envoi au LLM -5. **Gestion erreurs** : Messages clairs si commande échoue - -### Caractéristiques techniques : -- Exécution parallèle (performance) -- Timeout 30s par commande -- Buffer 10 MB max -- Variables env de settings.json -- Respect du cwd configuré - -## 📝 Exemple complet - -### Prompt direct -``` -Utilisateur actuel : !whoami -Dossier : !pwd -Fichiers : !`ls -1 | head -5` -``` - -### Commande markdown (`.claude/commands/info.md`) -```markdown ---- -description: Info projet ---- - -## Git -!`git branch --show-current` -!`git log --oneline -3` - -## Stats -!`find src -name "*.ts" | wc -l` fichiers TypeScript -``` - -Utilisation : `/info` - -## 🔧 API Changes - -**Breaking change mineur** : -```typescript -// Avant -interface SlashCommand { - prompt(args: string): string; -} - -// Maintenant -interface SlashCommand { - prompt(args: string): string | Promise; -} - -// Utilisation -const result = await command.prompt(args); // await requis -``` - -## ✨ Points forts - -1. **Simple à utiliser** : syntaxe intuitive `!commande` -2. **Flexible** : fonctionne partout (prompts, commandes) -3. **Performant** : exécution parallèle -4. **Robuste** : gestion d'erreurs complète -5. **Bien testé** : 11 tests unitaires -6. **Bien documenté** : guide utilisateur complet - -## 🚀 Utilisation immédiate - -L'implémentation est prête à l'emploi : - -```bash -# Build -pnpm build - -# Lancer -pnpm dev - -# Dans MagicCode : -Montre-moi le projet : !`ls -la` -``` - -## 📊 Statistiques - -- **Fichiers créés** : 4 -- **Fichiers modifiés** : 6 -- **Lignes de code** : ~350 -- **Tests** : 11 -- **Coverage** : 100% des fonctions principales - -## 🎉 Conclusion - -La commande `!` est entièrement implémentée, testée et documentée. Elle est prête à être utilisée en production. diff --git a/QUICK_SUMMARY.md b/QUICK_SUMMARY.md deleted file mode 100644 index fd95a95..0000000 --- a/QUICK_SUMMARY.md +++ /dev/null @@ -1,67 +0,0 @@ -# 🎯 Implémentation de la commande `!` - Résumé exécutif - -## ✅ TERMINÉ - -La commande shell `!` est **entièrement implémentée** dans l'extension ClaudeCode de MagicCode. - -## 🚀 Utilisation - -```bash -# Dans MagicCode : -Liste des fichiers : !`ls -la` -Utilisateur : !whoami - -# Ou via commande personnalisée : -/sysinfo -``` - -## 📦 Ce qui a été fait - -- ✅ **Code** : 350 lignes (2 fichiers sources) -- ✅ **Tests** : 11 tests unitaires (100% passing) -- ✅ **Docs** : 5 fichiers markdown -- ✅ **Exemple** : 1 commande de démo -- ✅ **Qualité** : TypeCheck ✓, Tests ✓, Build ✓ - -## 📁 Fichiers principaux - -``` -packages/ext-claudecode/src/ -├── shell-commands.ts # Cœur de la fonctionnalité -├── shell-commands.test.ts # Tests -└── SHELL_COMMANDS.md # Guide utilisateur - -.claude/commands/ -└── sysinfo.md # Exemple fonctionnel -``` - -## 🎯 Fonctionnalités - -1. **Syntaxe** : `!commande` ou `!`commande avec args`` -2. **Contextes** : Prompts directs + commandes markdown -3. **Sécurité** : Timeout 30s, buffer 10MB, gestion erreurs -4. **Integration** : Variables env, permissions existantes - -## ✅ Validation - -```bash -$ pnpm typecheck && pnpm test && pnpm build -✅ TypeCheck: Done -✅ Tests: 84/84 passing -✅ Build: Success -``` - -## 📖 Documentation - -- **Utilisateurs** : `packages/ext-claudecode/SHELL_COMMANDS.md` -- **Développeurs** : `IMPLEMENTATION_SUMMARY.md` -- **Tests** : `TEST_SHELL_COMMANDS.md` -- **Changements** : `FILES_CHANGES.md` - -## 🎉 Statut : PRODUCTION READY - -Aucun bug connu. Prêt à être utilisé immédiatement. - ---- - -**Question ?** Lire `IMPLEMENTATION_COMPLETE.md` pour tous les détails. diff --git a/README_IMPLEMENTATION.md b/README_IMPLEMENTATION.md deleted file mode 100644 index c1c0a10..0000000 --- a/README_IMPLEMENTATION.md +++ /dev/null @@ -1,166 +0,0 @@ -# Documentation de l'implémentation de la commande `!` - -Ce dossier contient la documentation complète de l'implémentation de la commande shell `!` dans MagicCode. - -## 📚 Index des documents - -### 🚀 Démarrage rapide -- **[QUICK_SUMMARY.md](QUICK_SUMMARY.md)** - Résumé ultra-condensé (1 page) - - ⏱️ Lecture : 2 minutes - - 👥 Public : Tout le monde - - 📌 À lire en premier - -### 📖 Documentation utilisateur -- **[packages/ext-claudecode/SHELL_COMMANDS.md](packages/ext-claudecode/SHELL_COMMANDS.md)** - Guide complet - - ⏱️ Lecture : 10 minutes - - 👥 Public : Utilisateurs de MagicCode - - 📌 Syntaxe, exemples, cas d'usage - -### 🔧 Documentation technique -- **[IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md)** - Vue technique - - ⏱️ Lecture : 15 minutes - - 👥 Public : Développeurs - - 📌 Architecture, API, intégration - -- **[IMPLEMENTATION_COMPLETE.md](IMPLEMENTATION_COMPLETE.md)** - Document final complet - - ⏱️ Lecture : 20 minutes - - 👥 Public : Équipe projet - - 📌 Vue exhaustive de l'implémentation - -### 📝 Historique et changements -- **[CHANGELOG_SHELL_COMMANDS.md](CHANGELOG_SHELL_COMMANDS.md)** - Historique détaillé - - ⏱️ Lecture : 10 minutes - - 👥 Public : Mainteneurs - - 📌 Chronologie, breaking changes - -- **[FILES_CHANGES.md](FILES_CHANGES.md)** - Liste exhaustive des fichiers - - ⏱️ Lecture : 5 minutes - - 👥 Public : Reviewers - - 📌 Tous les fichiers créés/modifiés - -### 🧪 Tests et validation -- **[TEST_SHELL_COMMANDS.md](TEST_SHELL_COMMANDS.md)** - Guide de test - - ⏱️ Lecture : 10 minutes - - 👥 Public : Testeurs, QA - - 📌 Scénarios de test, debugging - -- **[demo-shell-commands.sh](demo-shell-commands.sh)** - Script de démonstration - - ⏱️ Exécution : 30 secondes - - 👥 Public : Développeurs - - 📌 Validation automatique - -## 🗂️ Organisation du code - -``` -magiccode/ -├── packages/ext-claudecode/ -│ ├── src/ -│ │ ├── shell-commands.ts ⭐ Logique principale -│ │ ├── shell-commands.test.ts ⭐ Tests unitaires -│ │ ├── commands.ts ✏️ Modifié -│ │ ├── mode.ts ✏️ Modifié -│ │ └── index.ts ✏️ Modifié -│ └── SHELL_COMMANDS.md 📖 Guide utilisateur -│ -├── packages/cli/src/ -│ └── index.ts ✏️ Intégration CLI -│ -├── packages/core/src/ -│ └── types.ts ✏️ Type SlashCommand -│ -├── .claude/commands/ -│ └── sysinfo.md 💡 Exemple -│ -└── Documentation/ 📚 Ce dossier - ├── QUICK_SUMMARY.md - ├── IMPLEMENTATION_COMPLETE.md - ├── IMPLEMENTATION_SUMMARY.md - ├── CHANGELOG_SHELL_COMMANDS.md - ├── FILES_CHANGES.md - ├── TEST_SHELL_COMMANDS.md - └── demo-shell-commands.sh - -⭐ Nouveau fichier -✏️ Fichier modifié -📖 Documentation -💡 Exemple -``` - -## 🎯 Par où commencer ? - -### En tant qu'utilisateur -1. Lire [QUICK_SUMMARY.md](QUICK_SUMMARY.md) (2 min) -2. Consulter [SHELL_COMMANDS.md](packages/ext-claudecode/SHELL_COMMANDS.md) (10 min) -3. Essayer `/sysinfo` dans MagicCode - -### En tant que développeur -1. Lire [QUICK_SUMMARY.md](QUICK_SUMMARY.md) (2 min) -2. Consulter [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) (15 min) -3. Examiner le code dans `packages/ext-claudecode/src/shell-commands.ts` -4. Lancer les tests : `pnpm test shell-commands` - -### En tant que reviewer -1. Lire [IMPLEMENTATION_COMPLETE.md](IMPLEMENTATION_COMPLETE.md) (20 min) -2. Consulter [FILES_CHANGES.md](FILES_CHANGES.md) (5 min) -3. Suivre le guide [TEST_SHELL_COMMANDS.md](TEST_SHELL_COMMANDS.md) (10 min) -4. Exécuter `./demo-shell-commands.sh` - -### En tant que mainteneur -1. Lire [CHANGELOG_SHELL_COMMANDS.md](CHANGELOG_SHELL_COMMANDS.md) (10 min) -2. Consulter [FILES_CHANGES.md](FILES_CHANGES.md) pour les impacts (5 min) -3. Vérifier les tests : `pnpm typecheck && pnpm test && pnpm build` - -## ✅ Statut de l'implémentation - -| Aspect | Statut | Notes | -|--------|--------|-------| -| Code source | ✅ Terminé | 350 lignes, bien structuré | -| Tests unitaires | ✅ 11/11 passing | Coverage 100% | -| Tests intégration | ✅ 84/84 passing | Pas de régression | -| TypeCheck | ✅ OK | Tous les packages | -| Build | ✅ OK | Build success | -| Documentation utilisateur | ✅ Complète | Guide détaillé | -| Documentation technique | ✅ Complète | Architecture documentée | -| Exemples | ✅ Fonctionnels | Commande sysinfo | -| Production | ✅ **PRÊT** | Déployable immédiatement | - -## 🔍 Points clés - -### Fonctionnalités -- ✨ Syntaxe : `!commande` et `!`commande args`` -- ✨ Contextes : Prompts directs + commandes markdown -- ✨ Exécution parallèle de multiples commandes -- ✨ Gestion d'erreurs robuste -- ✨ Timeout 30s, buffer 10MB - -### Qualité -- ✅ 100% des tests passent -- ✅ Aucun warning TypeScript -- ✅ Code bien documenté -- ✅ Exemples fonctionnels -- ✅ Pas de breaking change majeur - -### Sécurité -- ⚠️ Exécution dans shell système (pas de sandbox) -- ✅ Timeout pour éviter blocages -- ✅ Buffer limité -- ✅ Gestion d'erreurs - -## 📞 Support - -- **Questions** : Consulter [SHELL_COMMANDS.md](packages/ext-claudecode/SHELL_COMMANDS.md) -- **Bugs** : Vérifier [TEST_SHELL_COMMANDS.md](TEST_SHELL_COMMANDS.md) -- **Développement** : Voir [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) -- **Historique** : Consulter [CHANGELOG_SHELL_COMMANDS.md](CHANGELOG_SHELL_COMMANDS.md) - -## 🎉 Conclusion - -L'implémentation de la commande `!` est **complète, testée et prête pour la production**. - -Tous les documents sont disponibles pour guider les utilisateurs, développeurs, testeurs et mainteneurs. - -**Next steps** : Merger et déployer ! 🚀 - ---- - -*Documentation générée le 12/10/2024* diff --git a/TEST_SHELL_COMMANDS.md b/TEST_SHELL_COMMANDS.md deleted file mode 100644 index 5ddf682..0000000 --- a/TEST_SHELL_COMMANDS.md +++ /dev/null @@ -1,114 +0,0 @@ -# Test de la commande `!` - Guide pratique - -## Test rapide - -```bash -# 1. Vérifier que tout compile et teste -pnpm typecheck && pnpm test && pnpm build - -# 2. Lancer MagicCode -pnpm dev - -# 3. Dans l'interface, tester les commandes suivantes: -``` - -## Exemples de test dans MagicCode - -### Test 1 : Commande simple -``` -Mon utilisateur : !whoami -``` -**Résultat attendu :** Affiche votre nom d'utilisateur - -### Test 2 : Commande avec arguments -``` -Fichiers du dossier : !`ls -la` -``` -**Résultat attendu :** Liste détaillée des fichiers - -### Test 3 : Commandes multiples -``` -User: !whoami -Dir: !pwd -Files: !`ls | wc -l` -``` -**Résultat attendu :** Les 3 commandes sont exécutées et leurs résultats affichés - -### Test 4 : Commande avec erreur -``` -Test erreur : !`commande_inexistante` -``` -**Résultat attendu :** Message d'erreur clair, pas de crash - -### Test 5 : Variables d'environnement -``` -Path: !`echo $PATH` -``` -**Résultat attendu :** Affiche la variable PATH - -### Test 6 : Commande personnalisée -``` -/sysinfo -``` -**Résultat attendu :** Exécute toutes les commandes `!` du fichier `.claude/commands/sysinfo.md` - -## Vérifications automatiques - -```bash -# Tests unitaires uniquement pour shell-commands -pnpm test shell-commands - -# Tous les tests -pnpm test - -# TypeCheck -pnpm typecheck -``` - -## Debugging - -Si problème, vérifier : - -1. **Syntaxe correcte** : `!commande` ou `!`commande avec args`` -2. **Backticks** : Utilisez ` pour les espaces -3. **Permissions** : La commande peut être exécutée dans votre terminal -4. **Timeout** : La commande se termine en moins de 30s - -## Structure du code - -``` -packages/ext-claudecode/src/ -├── shell-commands.ts # Logique principale -├── shell-commands.test.ts # Tests unitaires -├── commands.ts # Intégration dans les commandes -├── mode.ts # Configuration du mode -└── index.ts # Exports -``` - -## Logs de debug - -Pour voir les détails d'exécution, ajouter des console.log dans : -- `packages/cli/src/index.ts` ligne ~232 (expansion) -- `packages/ext-claudecode/src/shell-commands.ts` ligne ~60 (exécution) - -## Tests manuels recommandés - -- [ ] Commande simple sans arguments -- [ ] Commande avec arguments (backticks) -- [ ] Plusieurs commandes dans un prompt -- [ ] Commande qui échoue -- [ ] Commande longue (mais < 30s) -- [ ] Commande personnalisée (.claude/commands/) -- [ ] Commande avec variables $1, $2 + ! -- [ ] Vérifier les messages d'info affichés - -## Problèmes connus - -Aucun problème connu à ce stade. - -## Support - -Pour plus d'informations : -- Guide utilisateur : `packages/ext-claudecode/SHELL_COMMANDS.md` -- Documentation technique : `IMPLEMENTATION_SUMMARY.md` -- Liste des changements : `FILES_CHANGES.md` diff --git a/demo-shell-commands.sh b/demo-shell-commands.sh deleted file mode 100755 index e1809f8..0000000 --- a/demo-shell-commands.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash - -# Script de démonstration de la commande ! dans MagicCode -# Ce script teste les fonctionnalités d'exécution de commandes shell - -echo "🚀 Test de la commande shell ! dans MagicCode" -echo "================================================" -echo "" - -# Test 1 : Vérification que les tests passent -echo "✅ Test 1 : Vérification des tests unitaires" -cd /home/arnaud/Téléchargements/MagicCode/magiccode -pnpm test shell-commands --silent 2>&1 | grep "Test Files" -echo "" - -# Test 2 : Vérification du TypeCheck -echo "✅ Test 2 : Vérification TypeScript" -pnpm typecheck --silent 2>&1 | tail -1 -echo "" - -# Test 3 : Test de findShellCommands -echo "✅ Test 3 : Détection de commandes dans le texte" -cat > /tmp/test-shell-cmd.mjs << 'EOF' -import { findShellCommands } from './packages/ext-claudecode/src/shell-commands.js'; - -const text = "Utilisateur: !whoami\nDossier: !pwd\nFichiers: !`ls -la`"; -const matches = findShellCommands(text); - -console.log(`Trouvé ${matches.length} commandes:`); -matches.forEach((m, i) => { - console.log(` ${i+1}. "${m.match}" → commande: ${m.command}`); -}); -EOF - -# Note: Ce test nécessiterait une compilation préalable -# echo "Commandes détectées dans un texte exemple" -echo " (Voir les tests unitaires pour validation)" -echo "" - -# Test 4 : Vérification de l'exemple de commande -echo "✅ Test 4 : Commande d'exemple créée" -if [ -f ".claude/commands/sysinfo.md" ]; then - echo " ✓ .claude/commands/sysinfo.md existe" - echo " Contenu:" - head -5 .claude/commands/sysinfo.md | sed 's/^/ /' -else - echo " ✗ Fichier non trouvé" -fi -echo "" - -# Test 5 : Vérification de la documentation -echo "✅ Test 5 : Documentation créée" -docs=( - "packages/ext-claudecode/SHELL_COMMANDS.md" - "CHANGELOG_SHELL_COMMANDS.md" - "IMPLEMENTATION_SUMMARY.md" - "FILES_CHANGES.md" -) -for doc in "${docs[@]}"; do - if [ -f "$doc" ]; then - echo " ✓ $doc" - else - echo " ✗ $doc manquant" - fi -done -echo "" - -# Test 6 : Build -echo "✅ Test 6 : Vérification du build" -pnpm build --silent 2>&1 | grep -q "Build success" && echo " ✓ Build réussi" || echo " ✗ Build échoué" -echo "" - -# Test 7 : Simulation d'utilisation -echo "✅ Test 7 : Simulation d'exécution de commande shell" -echo " Exemple: !pwd → $(pwd)" -echo " Exemple: !whoami → $(whoami)" -echo " Exemple: !`echo hello` → hello" -echo "" - -# Résumé -echo "================================================" -echo "🎉 Implémentation de la commande ! terminée" -echo "" -echo "Pour tester en conditions réelles:" -echo " 1. pnpm dev" -echo " 2. Taper: Liste des fichiers : !`ls -la`" -echo " 3. Ou utiliser: /sysinfo" -echo "" -echo "Documentation:" -echo " - Guide: packages/ext-claudecode/SHELL_COMMANDS.md" -echo " - API: IMPLEMENTATION_SUMMARY.md" -echo "" diff --git a/packages/ext-claudecode/IMPLEMENTATION.md b/packages/ext-claudecode/IMPLEMENTATION.md deleted file mode 100644 index 379b8a1..0000000 --- a/packages/ext-claudecode/IMPLEMENTATION.md +++ /dev/null @@ -1,252 +0,0 @@ -# Implémentation du Lot 3 - -## Vue d'ensemble - -Le lot 3 a été complètement implémenté avec trois outils avancés : -- **WebFetch** : récupération d'URLs HTTP/HTTPS -- **TodoWrite** : gestion simple des listes TODO -- **Task** : gestion hiérarchique des tâches avec priorités - -## Fichiers créés - -### Outils (`packages/ext-claudecode/src/tools/`) - -1. **webfetch.ts** (4400 bytes) - - Récupère le contenu d'URLs - - Support GET/POST/PUT/DELETE/etc. - - En-têtes personnalisés - - Détection automatique du type de contenu (JSON, texte, binaire) - - Timeout configurable (30s par défaut) - - Limitation de la sortie (100 KB) - - Permission : "ask" (confirmation requise) - -2. **todowrite.ts** (8477 bytes) - - Stockage JSON persistant - - Actions : add, list, done, undone, block, unblock, remove, update, export-markdown - - Statuts : todo, done, blocked - - Export en markdown - - Permission : "auto" (direct, sans confirmation) - -3. **task.ts** (9830 bytes) - - Arborescence hiérarchique de tâches - - Statuts : todo, in-progress, done, blocked - - Priorités : low, normal, high, critical - - Assignations (utilisateurs) - - Actions : add, subtask, list, tree, status, assign, update, remove - - Calcul automatique du statut parent basé sur les enfants - - Permission : "auto" - -### Tests (`packages/ext-claudecode/src/tools/lot3.test.ts`) - -Tests complets pour les trois outils : -- **WebFetch** : 5 tests (GET simple, POST, erreurs URL, timeout) -- **TodoWrite** : 9 tests (CRUD complet, statuts, export markdown) -- **Task** : 9 tests (hiérarchies, assignations, arborescence) -- Total : 23 tests, tous passants - -### Documentation - -1. **LOT3.md** (5100 bytes) - - Documentation complète des trois outils - - Format JSON pour chaque action - - Exemples d'utilisation - - Affichage formaté avec symboles (✓, →, ⚠, ○) - -2. **IMPLEMENTATION.md** (ce fichier) - - Résumé des changements - - Structure des données - - Différences entre les outils - -## Fichiers modifiés - -### `packages/ext-claudecode/src/tools/index.ts` -- Ajout des imports pour webfetch, todowrite, task -- Mise à jour du commentaire de status -- Exports dans claudeCodeTools - -### `README.md` -- Nouvelle section "Extension ClaudeCode : outils (lot 1 + lot 3)" -- Listage des 9 outils disponibles -- Lien vers LOT3.md -- Mise à jour du "Reste à faire" - -## Architecture et patterns - -### Pattern de Tool (interface TypeScript) - -```typescript -export interface Tool { - spec: { - name: string; - description: string; - inputSchema: { /* JSON Schema */ }; - }; - permission: "auto" | "ask"; - describe?(input): string; - execute(input, ctx): Promise; -} -``` - -### Utilisation de helpers - -Les trois outils utilisent les helpers de `helpers.ts` : -- `str()` : extraction de paramètre string requis -- `optStr()` : paramètre string optionnel -- `optNum()` : paramètre number optionnel -- `optBool()` : paramètre boolean optionnel -- `resolvePath()` : résolution de chemin relatif/absolu - -### Stockage persistent - -- **TodoWrite** : JSON simple avec versioning et lastModified -- **Task** : JSON avec arborescence récursive (id unique par timestamp pour subtasks) - -### Format d'affichage - -Les trois outils retournent du texte formaté lisible : -``` -✓ [1] Tâche complète -→ [2] Tâche en cours -⚠ [3] Tâche bloquée -○ [4] Tâche à faire -``` - -## Intégration avec MagicCode - -### Mode ClaudeCode - -Les trois outils sont automatiquement disponibles via l'outil `Tool` du LLM : -1. Le LLM voit la liste complète des 9 outils disponibles -2. Décision autonome d'utiliser WebFetch, TodoWrite ou Task -3. Confirmation requise pour WebFetch (permission "ask") -4. Pas de confirmation pour TodoWrite/Task (permission "auto") - -### Flux d'utilisation - -``` -[Utilisateur] → Message - ↓ -[LLM] Décide d'utiliser WebFetch/TodoWrite/Task - ↓ -[UI] Demande confirmation (WebFetch uniquement) - ↓ -[Tool] Exécute l'action - ↓ -[LLM] Reçoit le résultat et continue - ↓ -[UI] Affiche la réponse finale -``` - -## Cas d'usage - -### WebFetch - -``` -"Récupère les stars de ce repo" -→ LLM : WebFetch https://api.github.com/repos/... -→ Résultat : JSON avec les données -``` - -### TodoWrite - -``` -"Ajoute une tâche 'Implémenter lot 3' à .todos.json" -→ LLM : TodoWrite action=add title=... file=... -→ Résultat : "Tâche ajoutée [1]" -``` - -### Task - -``` -"Crée un projet avec 3 sous-tâches assignées à Alice" -→ LLM : Task action=add title=... -→ LLM : Task action=subtask parent=1 title=... assignee=alice -→ LLM : Task action=subtask parent=1 title=... assignee=alice -→ Résultat : Arborescence créée -``` - -## Différences entre TodoWrite et Task - -| Aspect | TodoWrite | Task | -|--------|-----------|------| -| **Hiérarchie** | Aucune | Complète (parent/enfants) | -| **Priorités** | Aucune | 4 niveaux | -| **Assignations** | Aucune | Oui | -| **Statuts** | 3 (todo, done, blocked) | 4 (+ in-progress) | -| **Personne idéale** | Listes simples | Gestion de projets | -| **Complexité** | Basse | Moyenne | - -## Tests et validation - -```bash -# Exécuter les tests -pnpm test -- lot3 - -# Tests WebFetch -✓ devrait récupérer une URL valide (GET) -✓ devrait lever une erreur pour une URL invalide -✓ devrait lever une erreur pour une URL non accessible -✓ devrait supporter les requêtes POST -✓ should describe correctly - -# Tests TodoWrite -✓ devrait ajouter une tâche -✓ devrait lister les tâches -✓ devrait marquer une tâche comme complète -✓ devrait bloquer une tâche -✓ devrait supprimer une tâche -✓ devrait exporter en markdown -✓ devrait mettre à jour une tâche -✓ should describe correctly - -# Tests Task -✓ devrait créer une tâche -✓ devrait créer une sous-tâche -✓ devrait lister les tâches -✓ devrait afficher l'arborescence des tâches -✓ devrait mettre à jour le statut -✓ devrait assigner une tâche -✓ devrait supprimer une tâche -✓ should describe correctly -``` - -## Limitations actuelles - -1. **WebFetch** - - Pas de support du streaming (pour gros fichiers) - - Pas de cache des réponses - - Pas de retry automatique - -2. **TodoWrite** - - Pas de hiérarchie - - Pas de dépendances entre tâches - - Tags simples, sans recherche - -3. **Task** - - Pas de détection de dépendances circulaires - - Pas de synchronisation avec services externes - -## Reste à faire pour compléter lot 3+ - -- [ ] **WebFetch streaming** : support des gros fichiers -- [ ] **Task dépendances** : expliciter les relations -- [ ] **Hooks** : système de rappels (ex: on-status-change) -- [ ] **MCP** : Model Context Protocol integration -- [ ] **Sous-agents** : délégation de tâches -- [ ] **Synchronisation** : GitHub Issues, Jira, Trello -- [ ] **TodoWrite hiérarchie** : support parent/enfants -- [ ] **Cache** : persistance multi-sessions - -## Performances - -- **WebFetch** : timeout 30s, sortie max 100 KB -- **TodoWrite** : opérations O(n), pas de limitation -- **Task** : récursion jusqu'à profondeur ilimitée, O(n log n) pour tree - -## Sécurité - -- **WebFetch** : permission "ask" (confirmation avant chaque appel) -- **TodoWrite/Task** : permission "auto" (aucune confirmation) -- Chemins : résolus depuis cwd, ~ pour home -- Pas de risque d'injection (JSON Schema validation) - diff --git a/packages/ext-claudecode/LOT3.md b/packages/ext-claudecode/LOT3.md deleted file mode 100644 index b9aa1e3..0000000 --- a/packages/ext-claudecode/LOT3.md +++ /dev/null @@ -1,288 +0,0 @@ -# Lot 3 : WebFetch, TodoWrite et Task - -Implémentation complète du lot 3 avec trois outils : gestion des requêtes HTTP, gestion simple des listes TODO, et gestion hiérarchique des tâches avec priorités et assignations. - -## WebFetch - -Récupère le contenu d'une URL via HTTP/HTTPS. Retourne le statut, les en-têtes et le corps de la réponse. - -### Utilisation - -```typescript -{ - "url": "https://api.example.com/data", - "method": "GET", // optionnel : GET, POST, PUT, DELETE, etc. - "headers": {...}, // optionnel : en-têtes personnalisés - "body": "...", // optionnel : corps pour POST/PUT - "timeout": 30000 // optionnel : timeout en ms (30s par défaut) -} -``` - -### Exemples - -#### GET simple -```json -{ - "url": "https://github.com" -} -``` - -#### POST JSON -```json -{ - "url": "https://api.example.com/submit", - "method": "POST", - "headers": { - "Authorization": "Bearer token123" - }, - "body": "{\"name\": \"Alice\", \"age\": 30}" -} -``` - -### Comportement - -- **Réponse JSON** : formatée avec indentation -- **Réponse texte/XML** : retournée directe -- **Contenu binaire** : résumé avec taille -- **Timeout** : par défaut 30 secondes -- **Troncature** : sortie limitée à 100 KB - -### Permissions - -- **"ask"** : confirmation requise avant chaque appel (sécurité) - ---- - -## TodoWrite - -Gère une liste TODO persistante au format JSON avec exportation markdown. - -### Actions - -| Action | Description | -|--------|-------------| -| `add` | Ajoute une nouvelle tâche | -| `list` | Affiche toutes les tâches groupées par statut | -| `done` | Marque une tâche comme complète | -| `undone` | Remet une tâche à "À faire" | -| `block` | Marque une tâche comme bloquée | -| `unblock` | Débloque une tâche | -| `remove` | Supprime une tâche | -| `update` | Modifie une tâche existante | -| `export-markdown` | Exporte en fichier markdown | - -### Structure - -```json -{ - "version": 1, - "items": [ - { - "id": "1", - "status": "todo", // "todo" | "done" | "blocked" - "title": "Ma tâche", - "description": "...", // optionnel - "tags": ["urgent"], // optionnel - "createdAt": "2024-...", - "dueAt": "2024-..." // optionnel - } - ], - "lastModified": "2024-..." -} -``` - -### Exemples - -#### Ajouter une tâche simple -```json -{ - "file": ".todos.json", - "action": "add", - "title": "Implement WebFetch", - "tags": ["feature", "http"] -} -``` - -#### Lister les tâches -```json -{ - "file": ".todos.json", - "action": "list" -} -``` - ---- - -## Task - -Gère une arborescence hiérarchique de tâches avec priorités, assignations et statuts avancés. - -### Actions - -| Action | Description | -|--------|-------------| -| `add` | Crée une tâche principale | -| `subtask` | Crée une sous-tâche (requiert parent) | -| `list` | Affiche les tâches principales | -| `tree` | Affiche l'arborescence complète | -| `status` | Change le statut (todo, in-progress, done, blocked) | -| `assign` | Assigne une tâche à une personne | -| `update` | Modifie les détails d'une tâche | -| `remove` | Supprime une tâche | - -### Statuts - -- **todo** : À faire -- **in-progress** : En cours -- **done** : Complétée -- **blocked** : Bloquée - -### Priorités - -- **low** : Basse -- **normal** : Normal -- **high** : Haute -- **critical** : Critique - -### Structure - -```json -{ - "version": 1, - "tasks": [ - { - "id": "1", - "title": "Projet principal", - "status": "todo", - "priority": "high", - "description": "Description optionnelle", - "assignee": "alice", - "dueAt": "2024-12-31T23:59:59Z", - "tags": ["backend", "urgent"], - "createdAt": "2024-...", - "updatedAt": "2024-...", - "subtasks": [ - { - "id": "1-1", - "title": "Étape 1", - "status": "in-progress", - "priority": "high", - "parent": "1" - } - ] - } - ], - "lastModified": "2024-..." -} -``` - -### Exemples - -#### Créer une tâche avec priorité -```json -{ - "file": "tasks.json", - "action": "add", - "title": "Implémenter WebFetch", - "priority": "high", - "assignee": "alice", - "dueAt": "2024-12-15T17:00:00Z" -} -``` - -#### Créer une sous-tâche -```json -{ - "file": "tasks.json", - "action": "subtask", - "parent": "1", - "title": "Configurer authentification", - "priority": "high" -} -``` - -#### Voir l'arborescence -```json -{ - "file": "tasks.json", - "action": "tree" -} -``` - -Résultat : -``` -○ [1] Implémenter WebFetch [HIGH] (@alice) -├─ → [1-1] Configurer authentification [HIGH] -├─ ○ [1-2] Tester API externe [NORMAL] -└─ ✓ [1-3] Documentation [LOW] -``` - -#### Changer le statut -```json -{ - "file": "tasks.json", - "action": "status", - "id": "1", - "status": "in-progress" -} -``` - -#### Assigner à quelqu'un -```json -{ - "file": "tasks.json", - "action": "assign", - "id": "1", - "assignee": "bob" -} -``` - ---- - -## Intégration avec le LLM - -Les trois outils sont automatiquement disponibles dans le mode ClaudeCode et peuvent être utilisés par le LLM pour : - -### WebFetch -- Récupérer des API externes -- Valider des URLs -- Tester des endpoints API -- Scraper des données publiques - -### TodoWrite -- Créer des listes TODO simples -- Tracker des tâches de projet -- Exporter le backlog en markdown - -### Task -- Gérer des projets complexes avec hiérarchies -- Assigner du travail à des équipes -- Tracker les dépendances par la structure arborescente -- Gérer les priorités et blocages - ---- - -## Tests - -Exécutez les tests avec : -```bash -pnpm test -- lot3 -``` - -Les tests couvrent : -- ✅ WebFetch : GET/POST, gestion d'erreurs, types de contenu -- ✅ TodoWrite : CRUD complet, statuts, export markdown -- ✅ Task : hiérarchies, assignations, arborescence - ---- - -## Reste à faire - -- [ ] **WebFetch streaming** : support des gros fichiers -- [ ] **Task dépendances** : relations parent-enfant avancées -- [ ] **Task dépendances circulaires** : détection et avertissements -- [ ] **Hooks** : système de rappels sur les transitions de tâches -- [ ] **MCP** : intégration du Model Context Protocol -- [ ] **Sous-agents** : délégation de tâches à des sous-agents -- [ ] **Synchronisation externe** : GitHub Issues, Jira, Trello - diff --git a/packages/ext-claudecode/SHELL_COMMANDS.md b/packages/ext-claudecode/SHELL_COMMANDS.md deleted file mode 100644 index df63715..0000000 --- a/packages/ext-claudecode/SHELL_COMMANDS.md +++ /dev/null @@ -1,158 +0,0 @@ -# Commande Shell `!` dans MagicCode - -## Vue d'ensemble - -MagicCode permet d'exécuter des commandes shell directement dans vos prompts ou commandes personnalisées en utilisant la syntaxe `!`. - -## Syntaxe - -### Commande simple -``` -!commande -``` -Exécute `commande` et remplace `!commande` par sa sortie. - -**Exemple :** -``` -Voici mon utilisateur : !whoami -``` -Devient (après expansion) : -``` -Voici mon utilisateur : arnaud -``` - -### Commande avec espaces (backticks) -``` -!`commande avec arguments` -``` -Pour les commandes contenant des espaces ou des arguments, utilisez des backticks. - -**Exemple :** -``` -Liste des fichiers TypeScript : !`ls -la *.ts` -``` - -## Utilisation - -### 1. Dans les prompts directs - -Tapez directement dans l'interface MagicCode : -``` -Analyse le contenu du dossier actuel : !`ls -la` -``` - -MagicCode exécute la commande, affiche le résultat, puis envoie le prompt expansé au LLM. - -### 2. Dans les commandes personnalisées (`.claude/commands/`) - -Créez un fichier `.claude/commands/status.md` : -```markdown ---- -description: Affiche le statut du projet ---- - -État actuel du dépôt Git : - -!`git status --short` - -Derniers commits : - -!`git log --oneline -5` -``` - -Puis utilisez `/status` dans MagicCode. Les commandes shell seront exécutées et leurs résultats inclus dans le prompt envoyé au LLM. - -### 3. Combinaison avec des arguments - -Dans `.claude/commands/branch-info.md` : -```markdown ---- -description: Info sur une branche Git -argument-hint: ---- - -Informations sur la branche $1 : - -!`git log $1 --oneline -10` -``` - -Utilisez `/branch-info main` pour obtenir les informations sur la branche `main`. - -## Gestion des erreurs - -Si une commande échoue, elle est remplacée par `[ERREUR: message d'erreur]` dans le prompt, et MagicCode affiche un avertissement. - -**Exemple :** -``` -!`commande_inexistante` -``` -Devient : -``` -[ERREUR: Échec de la commande shell: ...] -``` - -## Permissions et sécurité - -- Les commandes shell respectent les permissions définies dans `.claude/settings.json` -- Les variables d'environnement de `settings.json` sont transmises -- Le dossier de travail est celui du lancement de MagicCode -- Timeout de 30 secondes par commande -- Buffer de sortie limité à 10 MB - -## Variables d'environnement - -Les commandes shell ont accès aux variables définies dans `.claude/settings.json` : - -```json -{ - "env": { - "PROJECT_NAME": "mon-projet", - "API_KEY": "..." - } -} -``` - -Puis utilisez : -``` -!`echo "Projet: $PROJECT_NAME"` -``` - -## Exemples pratiques - -### Analyse de performance -``` -Analyse les fichiers les plus volumineux : -!`du -sh * | sort -hr | head -10` -``` - -### État des dépendances -``` -Vérifie les dépendances obsolètes : -!`npm outdated` -``` - -### Tests -``` -Lance les tests et analyse les résultats : -!`npm test 2>&1` -``` - -### Information système -``` -CPU et mémoire : -!`top -bn1 | grep "Cpu(s)" | head -1` -``` - -## Limitations - -- Les commandes sont exécutées dans un shell système, pas dans un environnement isolé -- Pas de support pour les commandes interactives -- Les redirections (`>`, `>>`) et substitutions (`` `...` ``, `$(...)`) sont autorisées mais à vos risques -- Les commandes composées (`&&`, `;`, `|`) sont supportées - -## Notes techniques - -- Implémentation : `packages/ext-claudecode/src/shell-commands.ts` -- Regex de détection : `/!((?:`[^`]+`)|(?:[^\s]+))/g` -- Exécution via `child_process.exec` -- Les commandes multiples sont exécutées en parallèle pour plus de performance diff --git a/packages/ext-claudecode/src/shell-commands.test.ts b/packages/ext-claudecode/src/shell-commands.test.ts deleted file mode 100644 index 3be7e4f..0000000 --- a/packages/ext-claudecode/src/shell-commands.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { expandShellCommands, findShellCommands } from "./shell-commands"; - -describe("findShellCommands", () => { - it("détecte une commande simple", () => { - const matches = findShellCommands("Voici le résultat de !pwd"); - expect(matches).toHaveLength(1); - expect(matches[0]?.command).toBe("pwd"); - expect(matches[0]?.match).toBe("!pwd"); - }); - - it("détecte une commande avec backticks", () => { - const matches = findShellCommands("Liste: !`ls -la`"); - expect(matches).toHaveLength(1); - expect(matches[0]?.command).toBe("ls -la"); - expect(matches[0]?.match).toBe("!`ls -la`"); - }); - - it("détecte plusieurs commandes", () => { - const matches = findShellCommands("User: !whoami, Dir: !pwd"); - expect(matches).toHaveLength(2); - expect(matches[0]?.command).toBe("whoami,"); - expect(matches[1]?.command).toBe("pwd"); - }); - - it("gère les commandes en début et fin de ligne", () => { - const matches = findShellCommands("!echo test\nAutre ligne\n!date"); - expect(matches).toHaveLength(2); - expect(matches[0]?.command).toBe("echo"); - expect(matches[1]?.command).toBe("date"); - }); - - it("ne détecte rien sans commandes", () => { - const matches = findShellCommands("Pas de commande ici"); - expect(matches).toHaveLength(0); - }); - - it("ignore les ! suivis d'espace", () => { - const matches = findShellCommands("Wow ! Amazing"); - expect(matches).toHaveLength(0); - }); -}); - -describe("expandShellCommands", () => { - it("remplace une commande simple par sa sortie", async () => { - const result = await expandShellCommands("Echo: !`echo hello`", { cwd: process.cwd() }); - expect(result.expanded).toBe("Echo: hello"); - expect(result.executed).toHaveLength(1); - expect(result.executed[0]?.command).toBe("echo hello"); - expect(result.executed[0]?.output).toBe("hello"); - }); - - it("gère les erreurs de commande", async () => { - const result = await expandShellCommands("Erreur: !`exit 1`", { cwd: process.cwd() }); - expect(result.expanded).toContain("[ERREUR:"); - expect(result.executed[0]?.error).toBeDefined(); - }); - - it("remplace plusieurs commandes", async () => { - const result = await expandShellCommands("A: !`echo a` B: !`echo b`", { cwd: process.cwd() }); - expect(result.expanded).toBe("A: a B: b"); - expect(result.executed).toHaveLength(2); - }); - - it("ne modifie pas le texte sans commandes", async () => { - const result = await expandShellCommands("Texte normal", { cwd: process.cwd() }); - expect(result.expanded).toBe("Texte normal"); - expect(result.executed).toHaveLength(0); - }); - - it("transmet les variables d'environnement", async () => { - const result = await expandShellCommands("!`echo $TEST_VAR`", { - cwd: process.cwd(), - env: { TEST_VAR: "test123" }, - }); - expect(result.expanded).toBe("test123"); - }); -}); diff --git a/packages/ext-claudecode/src/shell-commands.ts b/packages/ext-claudecode/src/shell-commands.ts deleted file mode 100644 index 69d9c03..0000000 --- a/packages/ext-claudecode/src/shell-commands.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { exec } from "node:child_process"; -import { promisify } from "node:util"; - -const execAsync = promisify(exec); - -export interface ShellCommandMatch { - /** Commande complète trouvée (avec le ! ou !`...`) */ - match: string; - /** Commande shell à exécuter (sans le ! ou les backticks) */ - command: string; - /** Position de début dans la chaîne */ - start: number; - /** Position de fin dans la chaîne */ - end: number; -} - -/** - * Détecte les commandes shell dans un texte : - * - !commande (jusqu'à la fin de la ligne ou un espace) - * - !`commande avec espaces` - */ -export function findShellCommands(text: string): ShellCommandMatch[] { - const matches: ShellCommandMatch[] = []; - const regex = /!((?:`[^`]+`)|(?:[^\s]+))/g; - let match: RegExpExecArray | null; - - while ((match = regex.exec(text)) !== null) { - const full = match[0]; // ex: "!ls" ou "!`ls -la`" - const cmd = match[1]; // ex: "ls" ou "`ls -la`" - if (!cmd) continue; - const command = cmd.startsWith("`") && cmd.endsWith("`") ? cmd.slice(1, -1) : cmd; - - matches.push({ - match: full, - command, - start: match.index, - end: match.index + full.length, - }); - } - - return matches; -} - -/** - * Exécute une commande shell et retourne la sortie (stdout + stderr). - * Lance une erreur si la commande échoue. - */ -export async function executeShellCommand( - command: string, - options: { cwd: string; env?: Record; timeout?: number }, -): Promise { - const { cwd, env, timeout = 30000 } = options; - try { - const { stdout, stderr } = await execAsync(command, { - cwd, - env: { ...process.env, ...env }, - timeout, - maxBuffer: 1024 * 1024 * 10, // 10 MB - }); - // Combine stdout et stderr, utile pour les commandes qui écrivent sur stderr - const output = [stdout.trim(), stderr.trim()].filter(Boolean).join("\n"); - return output || "(commande exécutée sans sortie)"; - } catch (err: any) { - // Erreur d'exécution : code de sortie non nul ou timeout - const message = err.stderr || err.stdout || err.message; - throw new Error(`Échec de la commande shell: ${message}`); - } -} - -/** - * Remplace toutes les commandes shell (!...) dans un texte par leur sortie. - * Exécute les commandes en parallèle et retourne le texte transformé. - */ -export async function expandShellCommands( - text: string, - options: { cwd: string; env?: Record }, -): Promise<{ expanded: string; executed: Array<{ command: string; output: string; error?: string }> }> { - const matches = findShellCommands(text); - if (matches.length === 0) { - return { expanded: text, executed: [] }; - } - - // Exécuter toutes les commandes en parallèle - const results = await Promise.all( - matches.map(async (m) => { - try { - const output = await executeShellCommand(m.command, options); - return { command: m.command, output, error: undefined }; - } catch (err) { - return { command: m.command, output: "", error: (err as Error).message }; - } - }), - ); - - // Construire le texte expansé en remplaçant de la fin vers le début - // (pour ne pas décaler les indices) - let expanded = text; - for (let i = matches.length - 1; i >= 0; i--) { - const m = matches[i]; - const result = results[i]; - if (!m || !result) continue; // Protection TypeScript - const replacement = result.error ? `[ERREUR: ${result.error}]` : result.output; - expanded = expanded.slice(0, m.start) + replacement + expanded.slice(m.end); - } - - return { expanded, executed: results }; -} diff --git a/packages/ext-claudecode/src/tools/lot3.test.ts b/packages/ext-claudecode/src/tools/lot3.test.ts deleted file mode 100644 index 25fa29c..0000000 --- a/packages/ext-claudecode/src/tools/lot3.test.ts +++ /dev/null @@ -1,402 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach } from "vitest"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import { mkdir, rm } from "node:fs/promises"; -import { webfetchTool } from "./webfetch"; -import { todowriteTool } from "./todowrite"; -import { taskTool } from "./task"; - -const testDir = join(tmpdir(), "magiccode-test-lot3"); - -describe("WebFetch", () => { - beforeEach(async () => { - await mkdir(testDir, { recursive: true }); - }); - - afterEach(async () => { - await rm(testDir, { recursive: true, force: true }); - }); - - it("devrait récupérer une URL valide (GET)", async () => { - // Utiliser une API publique stable pour le test - const result = await webfetchTool.execute( - { url: "https://httpbin.org/get" }, - { cwd: testDir } - ); - expect(result).toContain("Status: 200"); - expect(result).toContain("[Headers]"); - expect(result).toContain("[Body]"); - }); - - it("devrait lever une erreur pour une URL invalide", async () => { - await expect( - webfetchTool.execute({ url: "not-a-url" }, { cwd: testDir }) - ).rejects.toThrow("URL invalide"); - }); - - it("devrait lever une erreur pour une URL non accessible", async () => { - await expect( - webfetchTool.execute({ url: "https://this-domain-does-not-exist-12345.com" }, { cwd: testDir }) - ).rejects.toThrow(); - }); - - it("devrait supporter les requêtes POST", async () => { - const result = await webfetchTool.execute( - { - url: "https://httpbin.org/post", - method: "POST", - body: '{"test": true}', - }, - { cwd: testDir } - ); - expect(result).toContain("Status: 200"); - }); - - it("should describe correctly", () => { - const desc = webfetchTool.describe?.({ url: "https://example.com", method: "POST" }); - expect(desc).toBe("WebFetch POST https://example.com"); - }); -}); - -describe("TodoWrite", () => { - beforeEach(async () => { - await mkdir(testDir, { recursive: true }); - }); - - afterEach(async () => { - await rm(testDir, { recursive: true, force: true }); - }); - - it("devrait ajouter une tâche", async () => { - const todoFile = join(testDir, "test.json"); - const result = await todowriteTool.execute( - { - file: todoFile, - action: "add", - title: "Ma première tâche", - }, - { cwd: testDir } - ); - expect(result).toContain("Tâche ajoutée"); - expect(result).toContain("Ma première tâche"); - }); - - it("devrait lister les tâches", async () => { - const todoFile = join(testDir, "test.json"); - - // Ajouter quelques tâches - await todowriteTool.execute( - { file: todoFile, action: "add", title: "Tâche 1" }, - { cwd: testDir } - ); - await todowriteTool.execute( - { file: todoFile, action: "add", title: "Tâche 2" }, - { cwd: testDir } - ); - - // Marquer une comme complète - await todowriteTool.execute( - { file: todoFile, action: "done", id: "1" }, - { cwd: testDir } - ); - - // Lister - const result = await todowriteTool.execute( - { file: todoFile, action: "list" }, - { cwd: testDir } - ); - - expect(result).toContain("À faire"); - expect(result).toContain("Complétées"); - expect(result).toContain("Tâche 1"); - expect(result).toContain("Tâche 2"); - }); - - it("devrait marquer une tâche comme complète", async () => { - const todoFile = join(testDir, "test.json"); - - await todowriteTool.execute( - { file: todoFile, action: "add", title: "Test complète" }, - { cwd: testDir } - ); - - const result = await todowriteTool.execute( - { file: todoFile, action: "done", id: "1" }, - { cwd: testDir } - ); - - expect(result).toContain("marquée complète"); - }); - - it("devrait bloquer une tâche", async () => { - const todoFile = join(testDir, "test.json"); - - await todowriteTool.execute( - { file: todoFile, action: "add", title: "Tâche bloquée" }, - { cwd: testDir } - ); - - const result = await todowriteTool.execute( - { file: todoFile, action: "block", id: "1" }, - { cwd: testDir } - ); - - expect(result).toContain("marquée bloquée"); - }); - - it("devrait supprimer une tâche", async () => { - const todoFile = join(testDir, "test.json"); - - await todowriteTool.execute( - { file: todoFile, action: "add", title: "À supprimer" }, - { cwd: testDir } - ); - - const result = await todowriteTool.execute( - { file: todoFile, action: "remove", id: "1" }, - { cwd: testDir } - ); - - expect(result).toContain("supprimée"); - - const listResult = await todowriteTool.execute( - { file: todoFile, action: "list" }, - { cwd: testDir } - ); - expect(listResult).toBe("Aucune tâche"); - }); - - it("devrait exporter en markdown", async () => { - const todoFile = join(testDir, "test.json"); - const mdFile = join(testDir, "test.md"); - - await todowriteTool.execute( - { file: todoFile, action: "add", title: "Tâche markdown" }, - { cwd: testDir } - ); - - const result = await todowriteTool.execute( - { file: todoFile, action: "export-markdown" }, - { cwd: testDir } - ); - - expect(result).toContain("exportée en markdown"); - }); - - it("devrait mettre à jour une tâche", async () => { - const todoFile = join(testDir, "test.json"); - - await todowriteTool.execute( - { file: todoFile, action: "add", title: "Original" }, - { cwd: testDir } - ); - - const result = await todowriteTool.execute( - { - file: todoFile, - action: "update", - id: "1", - title: "Modifiée", - description: "Nouvelle description", - }, - { cwd: testDir } - ); - - expect(result).toContain("mise à jour"); - expect(result).toContain("Modifiée"); - }); - - it("should describe correctly", () => { - const desc = todowriteTool.describe?.({ action: "add", file: "todos.json" }); - expect(desc).toBe("TodoWrite add todos.json"); - }); -}); - -describe("Task", () => { - beforeEach(async () => { - await mkdir(testDir, { recursive: true }); - }); - - afterEach(async () => { - await rm(testDir, { recursive: true, force: true }); - }); - - it("devrait créer une tâche", async () => { - const taskFile = join(testDir, "tasks.json"); - const result = await taskTool.execute( - { - file: taskFile, - action: "add", - title: "Implémenter WebFetch", - priority: "high", - }, - { cwd: testDir } - ); - expect(result).toContain("Tâche créée"); - expect(result).toContain("Implémenter WebFetch"); - }); - - it("devrait créer une sous-tâche", async () => { - const taskFile = join(testDir, "tasks.json"); - - // Créer la tâche parent - await taskTool.execute( - { - file: taskFile, - action: "add", - title: "Projet Web", - }, - { cwd: testDir } - ); - - // Créer une sous-tâche - const result = await taskTool.execute( - { - file: taskFile, - action: "subtask", - parent: "1", - title: "Configurer la base de données", - }, - { cwd: testDir } - ); - - expect(result).toContain("Sous-tâche créée"); - expect(result).toContain("parent: 1"); - }); - - it("devrait lister les tâches", async () => { - const taskFile = join(testDir, "tasks.json"); - - await taskTool.execute( - { - file: taskFile, - action: "add", - title: "Tâche 1", - priority: "high", - }, - { cwd: testDir } - ); - - const result = await taskTool.execute( - { file: taskFile, action: "list" }, - { cwd: testDir } - ); - - expect(result).toContain("Tâche 1"); - expect(result).toContain("[HIGH]"); - }); - - it("devrait afficher l'arborescence des tâches", async () => { - const taskFile = join(testDir, "tasks.json"); - - // Créer une hiérarchie - await taskTool.execute( - { - file: taskFile, - action: "add", - title: "Projet principal", - }, - { cwd: testDir } - ); - - // Créer une sous-tâche avec description pour simplifier le test - await taskTool.execute( - { - file: taskFile, - action: "subtask", - parent: "1", - title: "Step1", - }, - { cwd: testDir } - ); - - const result = await taskTool.execute( - { file: taskFile, action: "tree" }, - { cwd: testDir } - ); - - expect(result).toContain("Projet principal"); - expect(result).toContain("Step1"); - expect(result).toContain("├─"); - }); - - it("devrait mettre à jour le statut", async () => { - const taskFile = join(testDir, "tasks.json"); - - await taskTool.execute( - { - file: taskFile, - action: "add", - title: "À faire", - }, - { cwd: testDir } - ); - - const result = await taskTool.execute( - { - file: taskFile, - action: "status", - id: "1", - status: "in-progress", - }, - { cwd: testDir } - ); - - expect(result).toContain("in-progress"); - }); - - it("devrait assigner une tâche", async () => { - const taskFile = join(testDir, "tasks.json"); - - await taskTool.execute( - { - file: taskFile, - action: "add", - title: "Tâche", - }, - { cwd: testDir } - ); - - const result = await taskTool.execute( - { - file: taskFile, - action: "assign", - id: "1", - assignee: "alice", - }, - { cwd: testDir } - ); - - expect(result).toContain("alice"); - }); - - it("devrait supprimer une tâche", async () => { - const taskFile = join(testDir, "tasks.json"); - - await taskTool.execute( - { - file: taskFile, - action: "add", - title: "À supprimer", - }, - { cwd: testDir } - ); - - await taskTool.execute( - { file: taskFile, action: "remove", id: "1" }, - { cwd: testDir } - ); - - const listResult = await taskTool.execute( - { file: taskFile, action: "list" }, - { cwd: testDir } - ); - expect(listResult).toBe("Aucune tâche"); - }); - - it("should describe correctly", () => { - const desc = taskTool.describe?.({ action: "add", file: "tasks.json" }); - expect(desc).toBe("Task add tasks.json"); - }); -}); - diff --git a/packages/ext-claudecode/src/tools/task.ts b/packages/ext-claudecode/src/tools/task.ts deleted file mode 100644 index 0f4bb2a..0000000 --- a/packages/ext-claudecode/src/tools/task.ts +++ /dev/null @@ -1,312 +0,0 @@ -import { readFile, writeFile } from "node:fs/promises"; -import { dirname } from "node:path"; -import { mkdir } from "node:fs/promises"; -import type { Tool } from "@magiccode/core"; -import { resolvePath, optStr, str } from "./helpers"; - -interface TaskNode { - id: string; - title: string; - status: "todo" | "done" | "blocked" | "in-progress"; - description?: string; - priority?: "low" | "normal" | "high" | "critical"; - subtasks?: TaskNode[]; - parent?: string; - createdAt: string; - updatedAt: string; - dueAt?: string; - assignee?: string; - tags?: string[]; -} - -interface TaskList { - version: 1; - tasks: TaskNode[]; - lastModified: string; -} - -/** - * Calcule le statut d'une tâche parent en fonction de ses sous-tâches. - * - Toutes complètes : done - * - Aucune commencée : todo - * - Toutes bloquées : blocked - * - Sinon : in-progress - */ -function computeParentStatus(task: TaskNode): "todo" | "done" | "blocked" | "in-progress" { - if (!task.subtasks || task.subtasks.length === 0) { - return task.status; - } - - const statuses = new Set(task.subtasks.map((t) => t.status)); - - if (statuses.size === 1 && statuses.has("done")) { - return "done"; - } - if (statuses.has("done") && statuses.size > 1) { - return "in-progress"; - } - if (statuses.size === 1 && statuses.has("blocked")) { - return "blocked"; - } - if (statuses.size === 1 && statuses.has("todo")) { - return "todo"; - } - - return "in-progress"; -} - -/** - * Trouve une tâche récursivement. - */ -function findTask(tasks: TaskNode[], id: string): TaskNode | null { - for (const task of tasks) { - if (task.id === id) return task; - if (task.subtasks) { - const found = findTask(task.subtasks, id); - if (found) return found; - } - } - return null; -} - -/** - * Ajoute une sous-tâche à une tâche parent. - */ -function addSubtask(tasks: TaskNode[], parentId: string, subtask: TaskNode): boolean { - const parent = findTask(tasks, parentId); - if (!parent) return false; - if (!parent.subtasks) parent.subtasks = []; - parent.subtasks.push(subtask); - return true; -} - -/** - * Supprime une tâche récursivement. - */ -function removeTask(tasks: TaskNode[], id: string): boolean { - const idx = tasks.findIndex((t) => t.id === id); - if (idx >= 0) { - tasks.splice(idx, 1); - return true; - } - for (const task of tasks) { - if (task.subtasks && removeTask(task.subtasks, id)) { - return true; - } - } - return false; -} - -/** - * Formate l'affichage arborescent des tâches. - */ -function formatTaskTree(tasks: TaskNode[], indent = 0): string { - const lines: string[] = []; - for (const task of tasks) { - const prefix = indent === 0 ? "" : " ".repeat(indent - 1) + "├─ "; - const statusIcon = task.status === "done" ? "✓" : task.status === "in-progress" ? "→" : task.status === "blocked" ? "⚠" : "○"; - const priority = task.priority ? ` [${task.priority.toUpperCase()}]` : ""; - const assignee = task.assignee ? ` (@${task.assignee})` : ""; - lines.push(`${prefix}${statusIcon} [${task.id}] ${task.title}${priority}${assignee}`); - - if (task.description) { - lines.push(`${" ".repeat(indent)} > ${task.description}`); - } - - if (task.subtasks && task.subtasks.length > 0) { - lines.push(...formatTaskTree(task.subtasks, indent + 1).split("\n")); - } - } - return lines.join("\n"); -} - -export const taskTool: Tool = { - spec: { - name: "Task", - description: - "Gère une arborescence de tâches hiérarchiques (tâches + sous-tâches) avec statuts, priorités et assignations.", - inputSchema: { - type: "object", - properties: { - file: { - type: "string", - description: "Fichier des tâches (ex: tasks.json, relatif au dossier de lancement)", - }, - action: { - type: "string", - enum: ["add", "list", "subtask", "update", "remove", "status", "assign", "tree"], - description: "Action à effectuer", - }, - title: { type: "string", description: "Titre de la tâche" }, - id: { type: "string", description: "ID de la tâche" }, - parent: { type: "string", description: "ID du parent (pour créer une sous-tâche)" }, - status: { - type: "string", - enum: ["todo", "in-progress", "done", "blocked"], - description: "Nouveau statut", - }, - priority: { - type: "string", - enum: ["low", "normal", "high", "critical"], - description: "Priorité", - }, - description: { type: "string", description: "Description" }, - assignee: { type: "string", description: "Responsable" }, - dueAt: { type: "string", description: "Date limite (ISO 8601)" }, - tags: { type: "array", items: { type: "string" }, description: "Tags" }, - }, - required: ["file", "action"], - }, - }, - permission: "auto", - describe: (i) => `Task ${String(i.action)} ${String(i.file)}`, - async execute(input, ctx) { - const filePath = resolvePath(ctx.cwd, str(input, "file")); - const action = str(input, "action"); - - // Charger la liste existante - let list: TaskList; - try { - const content = await readFile(filePath, "utf8"); - list = JSON.parse(content); - } catch { - list = { - version: 1, - tasks: [], - lastModified: new Date().toISOString(), - }; - } - - let result: string; - - switch (action) { - case "add": { - const title = str(input, "title"); - const newId = String(Math.max(0, ...list.tasks.map((t) => parseInt(t.id, 10))) + 1); - const newTask: TaskNode = { - id: newId, - title, - status: "todo", - description: optStr(input, "description"), - priority: (input.priority as any) || "normal", - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - dueAt: optStr(input, "dueAt"), - assignee: optStr(input, "assignee"), - tags: (input.tags as string[]) || undefined, - }; - list.tasks.push(newTask); - result = `Tâche créée : [${newId}] ${title}`; - break; - } - - case "subtask": { - const parentId = str(input, "parent"); - const title = str(input, "title"); - const subtaskId = String(Date.now()); // ID unique basé sur le timestamp - const subtask: TaskNode = { - id: subtaskId, - title, - status: "todo", - parent: parentId, - description: optStr(input, "description"), - priority: (input.priority as any) || "normal", - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - dueAt: optStr(input, "dueAt"), - }; - if (addSubtask(list.tasks, parentId, subtask)) { - result = `Sous-tâche créée : [${subtaskId}] ${title} (parent: ${parentId})`; - } else { - throw new Error(`Tâche parent ${parentId} non trouvée`); - } - break; - } - - case "list": { - const tasks = list.tasks; - if (tasks.length === 0) { - result = "Aucune tâche"; - } else { - const lines: string[] = []; - lines.push("Tâches principales :"); - for (const task of tasks) { - const statusIcon = - task.status === "done" ? "✓" : task.status === "in-progress" ? "→" : task.status === "blocked" ? "⚠" : "○"; - const subtaskCount = task.subtasks ? ` (${task.subtasks.length} sous-tâches)` : ""; - const priority = task.priority ? ` [${task.priority.toUpperCase()}]` : ""; - lines.push( - ` ${statusIcon} [${task.id}] ${task.title}${priority}${subtaskCount}` + - (task.assignee ? ` (@${task.assignee})` : "") - ); - } - result = lines.join("\n"); - } - break; - } - - case "tree": { - result = formatTaskTree(list.tasks); - if (!result) result = "Aucune tâche"; - break; - } - - case "status": { - const id = str(input, "id"); - const newStatus = str(input, "status") as any; - const task = findTask(list.tasks, id); - if (!task) throw new Error(`Tâche ${id} non trouvée`); - task.status = newStatus; - task.updatedAt = new Date().toISOString(); - result = `Statut mis à jour : [${id}] → ${newStatus}`; - break; - } - - case "assign": { - const id = str(input, "id"); - const assignee = optStr(input, "assignee"); - const task = findTask(list.tasks, id); - if (!task) throw new Error(`Tâche ${id} non trouvée`); - task.assignee = assignee; - task.updatedAt = new Date().toISOString(); - result = assignee ? `Assignée à ${assignee} : [${id}]` : `Désassignée : [${id}]`; - break; - } - - case "update": { - const id = str(input, "id"); - const task = findTask(list.tasks, id); - if (!task) throw new Error(`Tâche ${id} non trouvée`); - if (input.title) task.title = String(input.title); - if (input.description !== undefined) task.description = optStr(input, "description"); - if (input.priority) task.priority = input.priority as any; - if (input.dueAt !== undefined) task.dueAt = optStr(input, "dueAt"); - task.updatedAt = new Date().toISOString(); - result = `Tâche mise à jour : [${id}] ${task.title}`; - break; - } - - case "remove": { - const id = str(input, "id"); - if (removeTask(list.tasks, id)) { - result = `Tâche supprimée : [${id}]`; - } else { - throw new Error(`Tâche ${id} non trouvée`); - } - break; - } - - default: - throw new Error(`Action inconnue : ${action}`); - } - - // Sauvegarder - if (!["list", "tree"].includes(action)) { - list.lastModified = new Date().toISOString(); - await mkdir(dirname(filePath), { recursive: true }); - await writeFile(filePath, JSON.stringify(list, null, 2), "utf8"); - } - - return result; - }, -};