| packages | ||
| .gitignore | ||
| btp_AI_tpl.json | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| screenshot2.png | ||
| tsconfig.base.json | ||
| tsconfig.json | ||
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
envdu mode ; uncdn'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é.
/clearl'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).
- OAuth client_credentials :
GET {url}/oauth/tokenavecAuthorization: Basic {basic}(token mis en cache, renouvelé sur expiration ou HTTP 401). - Découverte :
GET {AI_API_URL}/v2/lm/deployments(headerAI-Resource-Group,defaultsaufresourceGroupdans le JSON). - Appel du modèle sur son
deploymentUrlselon 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|denyau format Claude Code (Bash(npm run test:*),Edit(src/**),Read(./.env),Write) etenv(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êtedescriptionetargument-hint. Un sous-dossier préfixe le nom (commands/git/commit.md→/git:commit). Les nomshelp,clear,mode,model,exitsont réservés.skills/<nom>/SKILL.md: en-têtenameetdescription. Seule la liste est mise dans le prompt ; le contenu est chargé à la demande par l'outilSkill.
Outils TodoWrite et WebFetch (lot 3, première partie)
- TodoWrite : liste de tâches de la session (
pending/in_progress/completed, formeactiveFormpour 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_lengthcaractères renvoyés). Pas de JavaScript exécuté, pas de PDF ni d'images.- Confirmation demandée à chaque appel, sauf règle
allowdanssettings.json:"WebFetch(domain:docs.example.com)"(nom d'hôte exact, ou motif*.example.com) ;denyetaskfonctionnent 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é.
- Confirmation demandée à chaque appel, sauf règle
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-agentsagents/+ 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-claudecodelot 3 : TodoWrite, WebFetch, sous-agents, hooks, MCP -
Providers OpenAI et Ollama
-
Sessions (reprise), compaction du contexte, annulation (AbortSignal) depuis l'UI
