No description
Find a file
Arnaud a467318e35 feat(ext-claudecode): Ajout de la commande shell ! dans ClaudeCode
- Exécution de commandes shell inline avec `!commande` ou `!`commande args``
- Support dans les prompts directs et 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

Nouveaux fichiers:
- packages/cli/src/user-shell.ts
- packages/core/src/shell.ts et shell.test.ts
- packages/ext-claudecode/src/tools/todowrite.test.ts et webfetch.test.ts
- packages/ui/src/banner.tsx, pixels.ts et pixels.test.ts

Tests: ✅ Tous les tests passent
Breaking Changes: Mineur - SlashCommand.prompt() async
2026-10-12 09:16:26 +02:00
.claude/commands Migration Ink 2026-10-12 00:41:17 +02:00
packages feat(ext-claudecode): Ajout de la commande shell ! dans ClaudeCode 2026-10-12 09:16:26 +02:00
.gitignore Initial commit 2026-10-11 02:11:20 +02:00
btp_AI_tpl.json Initial commit 2026-10-11 02:11:20 +02:00
CHANGELOG_SHELL_COMMANDS.md Migration Ink 2026-10-12 00:41:17 +02:00
COMMIT_MESSAGE.md Migration Ink 2026-10-12 00:41:17 +02:00
demo-shell-commands.sh Migration Ink 2026-10-12 00:41:17 +02:00
FILES_CHANGES.md Migration Ink 2026-10-12 00:41:17 +02:00
IMPLEMENTATION_COMPLETE.md Migration Ink 2026-10-12 00:41:17 +02:00
IMPLEMENTATION_SUMMARY.md Migration Ink 2026-10-12 00:41:17 +02:00
package.json Initial commit 2026-10-11 02:11:20 +02:00
pnpm-lock.yaml feat(ext-claudecode): Ajout de la commande shell ! dans ClaudeCode 2026-10-12 09:16:26 +02:00
pnpm-workspace.yaml Initial commit 2026-10-11 02:11:20 +02:00
QUICK_SUMMARY.md Migration Ink 2026-10-12 00:41:17 +02:00
README.md feat(ext-claudecode): Ajout de la commande shell ! dans ClaudeCode 2026-10-12 09:16:26 +02:00
README_IMPLEMENTATION.md Migration Ink 2026-10-12 00:41:17 +02:00
TEST_SHELL_COMMANDS.md Migration Ink 2026-10-12 00:41:17 +02:00
tsconfig.base.json Migration Ink 2026-10-12 00:41:17 +02:00
tsconfig.json Migration Ink 2026-10-12 00:41:17 +02:00

MagicCode

Assistant IA en ligne de commande. Le mode (comportement de l'agent) vient d'une extension, le LLM se choisit indépendamment, l'interface utilise Ink (React pour CLI).

Démarrer

pnpm install
cp btp_AI_tpl.json btp_AI.json   # puis renseigner url, basic, serviceurls.AI_API_URL
pnpm dev                                  # mode claudecode ; le modèle est choisi dans la liste au démarrage
pnpm dev -- --model sapaicore:anthropic--claude-4.5-sonnet
pnpm dev -- --model anthropic:opus       # API Anthropic directe (ANTHROPIC_API_KEY)
pnpm test                                 # test de la boucle agent (provider factice)
pnpm build && node packages/cli/dist/index.js

Lancer MagicCode depuis un autre dossier

pnpm dev s'exécute depuis la racine du dépôt : le dossier de travail est alors cette racine (./btp_AI.json, ./CLAUDE.md… y sont cherchés). Pour utiliser MagicCode sur un autre projet ./X, lancez-le depuis ./X :

pnpm build
cd packages/cli && pnpm link --global     # une fois : installe la commande `magiccode`
cd ~/X && magiccode                       # le dossier de travail est ~/X
# ou sans installer :  cd ~/X && node /chemin/vers/magiccode/packages/cli/dist/index.js
# ou en développement : MAGICCODE_CWD=~/X pnpm --dir /chemin/vers/magiccode dev

Pourquoi pas pnpm --filter … dev : pnpm exécute alors le script depuis packages/cli, pas depuis le dossier où vous avez tapé la commande. MagicCode tient compte de MAGICCODE_CWD, puis de INIT_CWD (dossier où pnpm/npm a été lancé), puis de process.cwd().

Architecture

Paquet Rôle
core Contrats (LLMProvider, AgentMode, Extension, Tool, AgentUI), boucle agent, registre, chargement des extensions
providers Adaptateurs LLM : sapaicore (premier provider, voir ci-dessous), anthropic (direct), openai et ollama (à faire)
ui Interface Ink/React (journal, saisie, listes de choix, confirmations, spinner)
ext-claudecode Mode par défaut : CLAUDE.md, dossiers .claude (settings, commandes, skills) + outils Read/Glob/Grep/Write/Edit/Bash/TodoWrite/WebFetch
cli Point d'entrée : configuration, extensions, boucle de conversation

Résolution du mode et du modèle (le modèle n'a pas de défaut : s'il n'est pas défini, il est demandé) : flags CLI > variables MAGICCODE_MODE / MAGICCODE_MODEL

.magiccode/config.json (projet) > ~/.magiccode/config.json > défauts.

Extensions tierces : ~/.magiccode/extensions/<nom>/index.js (export default d'un objet Extension).

Interface (Ink)

L'interface est une application React rendue par Ink (Ink 7 : React ≥ 19.2 ; vérifiez la version de Node qu'il exige). Le CLI garde une façade impérative (InkUI : info, select, readInput, confirm, withSpinner…) au-dessus d'un UIStore sans dépendance à React, ce qui rend la logique testable (store.test.ts). Les composants (saisie, liste, confirmation, spinner) sont écrits sans bibliothèque tierce, pour ne dépendre que d'ink et de react. Un terminal interactif (TTY) est requis.

Présentation : la bannière d'accueil reprend le style « MAIA » : masque pixel-art à gauche (demi-blocs ▀▄█, 20 × 20 pixels), titre « MagicCode » en gros caractères pixel avec ombre et dégradé arc-en-ciel à droite, puis deux textes (vert, rose). Terminal d'au moins 80 colonnes pour la version complète ; entre 56 et 79 : sans le masque ; en dessous : cadre à double bordure compact, titre centré ; les messages d'information sont en bleu clair (LIGHT_BLUE dans packages/ui/src/colors.ts) ; une ligne vide sépare chaque message.

Contexte Touches
Saisie Entrée : envoyer · ←/→, Ctrl+A/E : se déplacer · ↑/↓ : historique · Ctrl+U/W : effacer · Ctrl+C ou Ctrl+D (saisie vide) : quitter · le collage multi-lignes est conservé
Liste (/model, /mode, choix initial) ↑/↓ (ou j/k) · Entrée : valider · Échap : annuler
Confirmation d'une action (Write, Edit, Bash…) o : autoriser · n ou Échap : refuser · Entrée seule est ignorée (réponse explicite exigée)
Pendant un tour de l'agent Ctrl+C : interrompt la requête et restaure la conversation avant cette demande

Dossier de base

Le dossier où MagicCode est lancé (ex. ./X) est la base de tous les chemins relatifs : fichiers lus, créés ou modifiés par les outils (Read, Write, Edit, Glob, Grep, Bash), ./btp_AI.json, .magiccode/config.json, CLAUDE.md et .claude/. Un chemin complet est utilisé tel quel (~/… désigne le dossier personnel). Ce dossier est capturé une fois au démarrage, affiché (« Dossier de travail : … ») et transmis aux outils et aux providers ; les règles de permissions (Read(./.env), Edit(src/**)) sont elles aussi relatives à ce dossier. Seuls ~/.claude et ~/.magiccode (config et extensions utilisateur) sont lus depuis le dossier personnel.

Commande ! : exécuter une commande shell

Quel que soit le mode chargé (ClaudeCode, Copilot…), !commande exécute la commande directement, sans passer par le modèle. Deux syntaxes :

Saisie Commande exécutée
!ls · !ls -la src tout ce qui suit le !
!'ls -la' le texte entre guillemets simples (délimite la commande avec ses paramètres)
!'ls' -la src · !'ls -la' | wc -l le texte entre guillemets, puis ce qui suit est ajouté comme paramètres : ls -la src, ls -la | wc -l
!'echo "l\'ami"' \' donne un guillemet simple littéral dans la commande
!'ls -la erreur (guillemet non fermé) : rien n'est exécuté

Le reste du comportement :

  • elle tourne dans le dossier de lancement (voir « Dossier de base ») avec les variables env du mode ; un cd n'a donc pas d'effet durable ;
  • stdout et stderr sont affichés dans l'ordre d'arrivée, avec le code de sortie en cas d'échec ; durée maximale 2 minutes ;
  • aucune confirmation n'est demandée (c'est vous qui la tapez) et les règles de permissions des outils ne s'appliquent pas ;
  • le résultat est ajouté au contexte de votre prochaine demande (jusqu'à 30 000 caractères, milieu tronqué au-delà), pour que le modèle sache ce qui a été lancé. /clear l'efface ;
  • Ctrl+C interrompt la commande ; ! seul affiche l'aide. Les programmes interactifs (vim, less, saisie au clavier…) ne sont pas pris en charge.

Skills : appel direct avec §

Quel que soit le mode chargé, §nom_du_skill [arguments] lance un skill de l'agent (ex. §sk_test) ; § seul liste les skills disponibles. Chaque mode expose ses skills via ModeInitResult.skills (contrat AgentSkill : name, description, invoke(args)), ce qui rend l'appel indépendant du format propre à l'agent. invoke retourne le prompt envoyé au LLM. En mode ClaudeCode, ce prompt contient les instructions du SKILL.md (avec $ARGUMENTS / ARGUMENTS:), sans passer par l'outil Skill du modèle. Les extensions Copilot, opencode, etc. n'ont qu'à renvoyer leurs propres skills sous cette forme.

Provider SAP AI Core / Generative AI Hub

Configuration : ./btp_AI.json (ou $MAGICCODE_BTP_CONFIG), modèle fourni dans btp_AI_tpl.json. Ne jamais versionner ce fichier (il est dans .gitignore).

  1. OAuth client_credentials : GET {url}/oauth/token avec Authorization: Basic {basic} (token mis en cache, renouvelé sur expiration ou HTTP 401).
  2. Découverte : GET {AI_API_URL}/v2/lm/deployments (header AI-Resource-Group, default sauf resourceGroup dans le JSON).
  3. Appel du modèle sur son deploymentUrl selon la famille : Claude → /converse (Bedrock), GPT → /chat/completions (Azure OpenAI). Les autres familles (Gemini, embeddings…) sont ignorées.

Choix du modèle : au démarrage (sauf si --model, MAGICCODE_MODEL ou une config le définit), MagicCode interroge tous les providers (déploiements SAP AI Core, et API Anthropic si ANTHROPIC_API_KEY est définie) et demande de choisir le modèle de la session. /model rouvre cette liste en cours de session (la conversation est conservée). Un provider injoignable donne un avertissement sans bloquer les autres. Spécification explicite : sapaicore:<nom du déploiement>.

Extension ClaudeCode : dossiers .claude (lot 2)

Les dossiers .claude sont lus dans cet ordre (le plus spécifique l'emporte) : ~/.claude, puis ceux de la racine jusqu'au dossier courant.

  • settings.json / settings.local.json : permissions.allow|ask|deny au format Claude Code (Bash(npm run test:*), Edit(src/**), Read(./.env), Write) et env (transmis à Bash). Priorité deny > ask > allow. Pour Bash, une règle allow ne couvre une commande composée (&&, ;, |) que si chaque partie est autorisée, et jamais une commande avec redirection ou substitution (>, $(…), backticks). Les règles deny sont du « meilleur effort » : elles ne remplacent pas un vrai bac à sable.
  • commands/**/*.md : slash-commandes. $ARGUMENTS, $1…$9 ; en-tête description et argument-hint. Un sous-dossier préfixe le nom (commands/git/commit.md → /git:commit). Les noms help, clear, mode, model, exit sont réservés.
  • skills/<nom>/SKILL.md : en-tête name et description. Seule la liste est mise dans le prompt ; le contenu est chargé à la demande par l'outil Skill.

Outils TodoWrite et WebFetch (lot 3, première partie)

  • TodoWrite : liste de tâches de la session (pending / in_progress / completed, forme activeForm pour la tâche en cours). Chaque appel remplace la liste ; le résultat (☐ ▶ ☑) est affiché à l'utilisateur et renvoyé au modèle. Un avertissement est ajouté si plusieurs tâches sont « en cours ».
  • WebFetch : télécharge une URL http(s) (HTML converti en Markdown avec turndown, JSON mis en forme, texte brut ; 5 Mo et 30 s maximum, max_length caractères renvoyés). Pas de JavaScript exécuté, pas de PDF ni d'images.
    • Confirmation demandée à chaque appel, sauf règle allow dans settings.json : "WebFetch(domain:docs.example.com)" (nom d'hôte exact, ou motif *.example.com) ; deny et ask fonctionnent de même.
    • Une redirection vers un autre domaine n'est pas suivie : l'outil renvoie la nouvelle URL, que le modèle doit rappeler (ce qui repasse par la confirmation).
    • Le contenu est signalé au modèle comme non fiable (risque d'injection de prompt) ; il ne passe par aucun second modèle de résumé.

Reste à faire

  • Provider SAP AI Core : streaming (actuellement une réponse complète par appel), autres familles (Gemini), validation sur un vrai service

  • ext-claudecode : lots 1 et 2 terminés, lot 3 : TodoWrite et WebFetch faits (reste : sous-agents agents/ + outil Task, hooks, serveurs MCP) (Glob/Grep en JS pur sans ripgrep ; à l'initialisation, ce qui est trouvé et chargé est listé, sinon un avertissement). Pas encore gérés dans les commandes : allowed-tools, model, @fichier, !commande``

  • ext-claudecode lot 3 : TodoWrite, WebFetch, sous-agents, hooks, MCP

  • Providers OpenAI et Ollama

  • Sessions (reprise), compaction du contexte, annulation (AbortSignal) depuis l'UI