TheShellMaster commited on
Commit
f9cace8
·
verified ·
1 Parent(s): 7c5138e

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. app.py +10 -1
  2. index.js +850 -33
app.py CHANGED
@@ -38,6 +38,12 @@ async def chat(request: Request):
38
  messages = body.get("messages", [])
39
  client_tools = body.get("tools", [])
40
 
 
 
 
 
 
 
41
  # Associer les outils locaux du client et l'outil de recherche web du serveur
42
  all_tools = list(client_tools)
43
  search_tool_def = {
@@ -62,9 +68,12 @@ async def chat(request: Request):
62
  # Boucle d'agent côté serveur pour exécuter search_web de manière transparente
63
  while True:
64
  response = client.chat_completion(
 
65
  messages=messages,
66
  tools=all_tools,
67
- max_tokens=2048,
 
 
68
  stream=False
69
  )
70
  choice = response.choices[0]
 
38
  messages = body.get("messages", [])
39
  client_tools = body.get("tools", [])
40
 
41
+ # dynamic inference parameters
42
+ model = body.get("model", "Qwen/Qwen2.5-Coder-32B-Instruct")
43
+ temperature = body.get("temperature", None)
44
+ top_p = body.get("top_p", None)
45
+ max_tokens = body.get("max_tokens", 2048)
46
+
47
  # Associer les outils locaux du client et l'outil de recherche web du serveur
48
  all_tools = list(client_tools)
49
  search_tool_def = {
 
68
  # Boucle d'agent côté serveur pour exécuter search_web de manière transparente
69
  while True:
70
  response = client.chat_completion(
71
+ model=model,
72
  messages=messages,
73
  tools=all_tools,
74
+ max_tokens=max_tokens,
75
+ temperature=temperature,
76
+ top_p=top_p,
77
  stream=False
78
  )
79
  choice = response.choices[0]
index.js CHANGED
@@ -26,6 +26,37 @@ marked.setOptions({
26
  const AUTHOR = "DJAKOUA KWANKAM";
27
  const APP_NAME = "Cypher Coder";
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  // Banner ASCII Art pour l'interface de démarrage
30
  const BANNER = chalk.cyan.bold(`
31
  _____ _---------------+
@@ -150,10 +181,18 @@ const tools = [
150
 
151
  // Outil d'exécution d'API robuste via curl pour contourner les problèmes de socket de Node.js
152
  function callApiViaCurl(messages, clientTools) {
153
- const payload = JSON.stringify({ messages, tools: clientTools });
 
 
 
 
 
 
 
154
  const escapedPayload = payload.replace(/'/g, "'\\''");
155
  const command = `curl -s -X POST -H "Content-Type: application/json" -d '${escapedPayload}' https://theshellmaster-cypher-coder.hf.space/api/chat`;
156
 
 
157
  const output = execSync(command).toString();
158
  try {
159
  const responseJson = JSON.parse(output);
@@ -672,7 +711,6 @@ Le répertoire de travail actuel contient les dossiers et fichiers suivants au p
672
  Sois précis, concis et direct. Formate tes réponses en Markdown standard.`;
673
  }
674
 
675
- let chatMessages = [];
676
 
677
  function initChat() {
678
  chatMessages = [{"role": "system", "content": getSystemPrompt()}];
@@ -692,6 +730,8 @@ async function runAgentTurn() {
692
  chatMessages.push(replyMessage);
693
 
694
  if (replyMessage.content) {
 
 
695
  console.log(chalk.green(`\n🤖 Cypher : `));
696
  // Rendre le Markdown de l'IA avec formatage ANSI coloré
697
  console.log(marked(replyMessage.content));
@@ -725,6 +765,807 @@ async function runAgentTurn() {
725
  }
726
  }
727
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
728
  async function askQuestion() {
729
  const { userInput } = await inquirer.prompt([
730
  {
@@ -741,40 +1582,16 @@ async function askQuestion() {
741
  return askQuestion();
742
  }
743
 
744
- if (text === '/exit' || text === '/quit') {
745
- console.log(chalk.gray("Fermeture de Cypher Coder. À bientôt !"));
746
- process.exit(0);
747
- }
748
-
749
- if (text === '/clear') {
750
- console.clear();
751
- initChat();
752
- console.log(BANNER);
753
- console.log(chalk.green("Discussion réinitialisée et répertoire indexé.\n"));
754
- return askQuestion();
755
- }
756
-
757
- if (text === '/help') {
758
- console.log(chalk.yellow("\nCommandes disponibles :"));
759
- console.log(" /help - Affiche ce menu d'aide");
760
- console.log(" /status - Affiche le dossier actif, le backend et l'index de fichiers");
761
- console.log(" /clear - Efface l'écran et réinitialise la discussion et le contexte");
762
- console.log(" /exit - Quitte l'application\n");
763
- return askQuestion();
764
  }
765
 
766
- if (text === '/status') {
767
- const dirContext = getCurrentDirectoryContext();
768
- console.log(chalk.yellow("\n=== Statut de la Session ==="));
769
- console.log(` Dossier de travail : ${chalk.cyan(path.resolve("."))}`);
770
- console.log(` Backend Space : ${chalk.cyan("https://theshellmaster-cypher-coder.hf.space")}`);
771
- console.log(` Modèle utilisé : ${chalk.cyan("Qwen/Qwen2.5-Coder-32B-Instruct")}`);
772
- console.log(` Auteur : ${chalk.cyan("DJAKOUA KWANKAM (IUD)")}`);
773
- console.log(` Fichiers suivis : ${chalk.dim(dirContext)}\n`);
774
- return askQuestion();
775
- }
776
 
777
- // Ajouter le message utilisateur et démarrer le tour d'agent
778
  chatMessages.push({"role": "user", "content": text});
779
  await runAgentTurn();
780
 
 
26
  const AUTHOR = "DJAKOUA KWANKAM";
27
  const APP_NAME = "Cypher Coder";
28
 
29
+ // Global Session State & Config
30
+ let chatMessages = [];
31
+ let lastUserInput = "";
32
+ let lastAssistantResponse = "";
33
+ let commandHistory = [];
34
+ let savedContexts = {};
35
+ let loadedFiles = [];
36
+ let macros = {};
37
+ let logs = [];
38
+
39
+ const sessionConfig = {
40
+ model: "Qwen/Qwen2.5-Coder-32B-Instruct",
41
+ temperature: 0.7,
42
+ top_p: 0.9,
43
+ max_tokens: 2048,
44
+ stream: false,
45
+ sandbox: false,
46
+ verbose: false,
47
+ silent: false,
48
+ color: true,
49
+ theme: "dark",
50
+ format: "md",
51
+ lang: "fr",
52
+ env: {}
53
+ };
54
+
55
+ function addLog(level, message) {
56
+ const logItem = `[${new Date().toISOString()}] [${level}] ${message}`;
57
+ logs.push(logItem);
58
+ }
59
+
60
  // Banner ASCII Art pour l'interface de démarrage
61
  const BANNER = chalk.cyan.bold(`
62
  _____ _---------------+
 
181
 
182
  // Outil d'exécution d'API robuste via curl pour contourner les problèmes de socket de Node.js
183
  function callApiViaCurl(messages, clientTools) {
184
+ const payload = JSON.stringify({
185
+ messages,
186
+ tools: clientTools,
187
+ model: sessionConfig.model,
188
+ temperature: sessionConfig.temperature,
189
+ top_p: sessionConfig.top_p,
190
+ max_tokens: sessionConfig.max_tokens
191
+ });
192
  const escapedPayload = payload.replace(/'/g, "'\\''");
193
  const command = `curl -s -X POST -H "Content-Type: application/json" -d '${escapedPayload}' https://theshellmaster-cypher-coder.hf.space/api/chat`;
194
 
195
+ addLog("DEBUG", `Envoi payload API vers HF Space: modèle=${sessionConfig.model}, température=${sessionConfig.temperature}`);
196
  const output = execSync(command).toString();
197
  try {
198
  const responseJson = JSON.parse(output);
 
711
  Sois précis, concis et direct. Formate tes réponses en Markdown standard.`;
712
  }
713
 
 
714
 
715
  function initChat() {
716
  chatMessages = [{"role": "system", "content": getSystemPrompt()}];
 
730
  chatMessages.push(replyMessage);
731
 
732
  if (replyMessage.content) {
733
+ lastAssistantResponse = replyMessage.content;
734
+ addLog("INFO", "Réponse de l'assistant enregistrée.");
735
  console.log(chalk.green(`\n🤖 Cypher : `));
736
  // Rendre le Markdown de l'IA avec formatage ANSI coloré
737
  console.log(marked(replyMessage.content));
 
765
  }
766
  }
767
 
768
+ async function handleSlashCommand(text) {
769
+ if (!text.startsWith('/')) {
770
+ return false;
771
+ }
772
+
773
+ const parts = text.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || [];
774
+ if (parts.length === 0) return true;
775
+
776
+ const commandName = parts[0];
777
+ const rawArgs = parts.slice(1).map(a => a.replace(/^["']|["']$/g, ''));
778
+
779
+ addLog("INFO", `Commande slash reçue: ${text}`);
780
+ commandHistory.push(text);
781
+
782
+ const cleanArgs = [];
783
+ const flags = {};
784
+ for (let i = 0; i < rawArgs.length; i++) {
785
+ if (rawArgs[i].startsWith('--')) {
786
+ const key = rawArgs[i].slice(2);
787
+ if (rawArgs[i+1] && !rawArgs[i+1].startsWith('--')) {
788
+ flags[key] = rawArgs[++i];
789
+ } else {
790
+ flags[key] = true;
791
+ }
792
+ } else {
793
+ cleanArgs.push(rawArgs[i]);
794
+ }
795
+ }
796
+
797
+ switch (commandName.toLowerCase()) {
798
+ // --- 1. Contrôle de session
799
+ case '/help':
800
+ console.log(chalk.cyan.bold("\n📚 CYPHER CODER CLI - COMMANDES DISPONIBLES :"));
801
+
802
+ console.log(chalk.yellow("\n🎛️ Session :"));
803
+ console.log(" /help - Affiche ce menu d'aide");
804
+ console.log(" /exit, /quit - Quitte proprement l'agent");
805
+ console.log(" /clear - Efface l'écran");
806
+ console.log(" /reset - Réinitialise la discussion et l'historique");
807
+ console.log(" /restart - Redémarre proprement la session");
808
+ console.log(" /version - Affiche la version actuelle");
809
+ console.log(" /about - Infos sur le projet");
810
+ console.log(" /status - Affiche le statut complet");
811
+
812
+ console.log(chalk.yellow("\n💬 Mémoire et Contexte :"));
813
+ console.log(" /context - Affiche les fichiers chargés en contexte");
814
+ console.log(" /context clear - Efface le contexte de fichiers");
815
+ console.log(" /context save <nom> - Sauvegarde la session actuelle");
816
+ console.log(" /context load <nom> - Charge une session sauvegardée");
817
+ console.log(" /context list - Liste les sessions sauvegardées");
818
+ console.log(" /memory - Affiche la mémoire système + messages");
819
+ console.log(" /memory clear - Efface les messages d'historique");
820
+ console.log(" /tokens - Affiche les statistiques de tokens");
821
+
822
+ console.log(chalk.yellow("\n📜 Historique :"));
823
+ console.log(" /history - Affiche tout l'historique");
824
+ console.log(" /history clear - Efface l'historique enregistré");
825
+ console.log(" /history save <fichier> - Exporte l'historique dans un fichier");
826
+ console.log(" /history load <fichier> - Importe un historique");
827
+ console.log(" /history search <terme> - Cherche dans l'historique");
828
+ console.log(" /last - Affiche la dernière réponse de l'agent");
829
+ console.log(" /redo - Relance la dernière requête");
830
+ console.log(" /undo - Annule la dernière interaction");
831
+
832
+ console.log(chalk.yellow("\n🤖 Modèle et Configuration :"));
833
+ console.log(" /model - Affiche le modèle utilisé");
834
+ console.log(" /model list - Liste les modèles supportés");
835
+ console.log(" /model set <nom> - Change de modèle");
836
+ console.log(" /model info - Affiche les infos du modèle");
837
+ console.log(" /temperature <valeur> - Ajuste la température (0.0 - 1.0)");
838
+ console.log(" /top_p <valeur> - Ajuste le top_p");
839
+ console.log(" /max_tokens <valeur> - Ajuste la limite de tokens");
840
+ console.log(" /system - Affiche le prompt système");
841
+ console.log(" /system set <prompt> - Modifie le prompt système");
842
+ console.log(" /system reset - Réinitialise le prompt système");
843
+ console.log(" /stream <on|off> - Active/désactive le streaming");
844
+
845
+ console.log(chalk.yellow("\n📁 Fichiers :"));
846
+ console.log(" /file load <chemin> - Charge le fichier dans le contexte");
847
+ console.log(" /file read <chemin> - Lit et affiche un fichier");
848
+ console.log(" /file write <chemin> - Écrit la dernière réponse dans un fichier");
849
+ console.log(" /file append <chemin> - Ajoute la dernière réponse à un fichier");
850
+ console.log(" /file list - Liste les fichiers chargés");
851
+ console.log(" /file clear - Vide le contexte de fichiers");
852
+ console.log(" /file diff <f1> <f2> - Compare deux fichiers");
853
+ console.log(" /upload <chemin> - Simule l'envoi d'un fichier");
854
+ console.log(" /download <nom> - Télécharge un fichier");
855
+
856
+ console.log(chalk.yellow("\n⚡ Code et Commandes :"));
857
+ console.log(" /run - Exécute le dernier bloc de code");
858
+ console.log(" /run <lang> <code> - Exécute le code fourni");
859
+ console.log(" /exec <commande> - Lance une commande système");
860
+ console.log(" /shell - Lance un terminal interactif");
861
+ console.log(" /repl <lang> - Lance un REPL (ex: node, python)");
862
+ console.log(" /eval <expression> - Évalue une expression mathématique");
863
+ console.log(" /sandbox <on|off> - Active/désactive l'isolation");
864
+ console.log(" /output - Affiche la dernière sortie");
865
+ console.log(" /output clear - Efface la dernière sortie");
866
+
867
+ console.log(chalk.yellow("\n🔌 Outils et Recherche :"));
868
+ console.log(" /tools - Liste les outils activés");
869
+ console.log(" /tool info <nom> - Affiche la description d'un outil");
870
+ console.log(" /tool enable/disable <n> - Active/désactive un outil");
871
+ console.log(" /plugin list/install/rm - Gère les plugins");
872
+ console.log(" /web search <requête> - Recherche en ligne");
873
+ console.log(" /web fetch <url> - Récupère le contenu d'une URL");
874
+
875
+ console.log(chalk.yellow("\n🎨 Thème et Affichage :"));
876
+ console.log(" /theme <dark|light> - Change le thème");
877
+ console.log(" /theme list - Liste les thèmes");
878
+ console.log(" /format <md|plain|json> - Format des réponses");
879
+ console.log(" /wrap <on|off> - Retour à la ligne automatique");
880
+ console.log(" /verbose <on|off> - Mode verbeux");
881
+ console.log(" /silent <on|off> - Mode silencieux");
882
+ console.log(" /color <on|off> - Colorisation syntaxique");
883
+ console.log(" /lang <fr|en> - Change la langue");
884
+
885
+ console.log(chalk.yellow("\n🔐 Configuration et Variable d'env :"));
886
+ console.log(" /config - Affiche la configuration");
887
+ console.log(" /config set <key> <val> - Modifie la configuration");
888
+ console.log(" /config reset - Réinitialise la configuration");
889
+ console.log(" /env list - Liste les variables d'env");
890
+ console.log(" /env set <VAR> <val> - Définit une variable d'env");
891
+ console.log(" /api key show/set/clear - Gère les clés d'API");
892
+
893
+ console.log(chalk.yellow("\n📊 Monitoring et Debug :"));
894
+ console.log(" /debug <on|off> - Active le mode debug");
895
+ console.log(" /log - Affiche les logs");
896
+ console.log(" /log clear/save - Efface ou enregistre les logs");
897
+ console.log(" /benchmark - Teste la latence API");
898
+ console.log(" /ping - Teste la connexion réseau");
899
+ console.log(" /stats - Statistiques de session");
900
+ console.log(" /trace - Trace des appels");
901
+ console.log(" /inspect <var> - Inspecte la configuration interne");
902
+
903
+ console.log(chalk.yellow("\n🔁 Automatisation :"));
904
+ console.log(" /macro save/run/list/del - Gère les macros");
905
+ console.log(" /pipe <cmd1> | <cmd2> - Chaîne deux commandes");
906
+ console.log(" /loop <n> <commande> - Répète une commande");
907
+ console.log(" /schedule <cron> <cmd> - Planifie une tâche");
908
+ console.log(" /watch <cmd> - Surveille les fichiers");
909
+ console.log(" /batch <fichier> - Exécute des commandes en lot\n");
910
+ break;
911
+
912
+ case '/exit':
913
+ case '/quit':
914
+ console.log(chalk.gray("Fermeture de Cypher Coder. À bientôt !"));
915
+ process.exit(0);
916
+
917
+ case '/clear':
918
+ console.clear();
919
+ console.log(BANNER);
920
+ console.log(chalk.green("Écran nettoyé.\n"));
921
+ break;
922
+
923
+ case '/reset':
924
+ initChat();
925
+ commandHistory = [];
926
+ loadedFiles = [];
927
+ console.log(chalk.green("Session réinitialisée. Historique et contexte effacés.\n"));
928
+ break;
929
+
930
+ case '/restart':
931
+ console.log(chalk.yellow("Redémarrage de l'agent en cours..."));
932
+ initChat();
933
+ console.clear();
934
+ console.log(BANNER);
935
+ console.log(chalk.green("Cypher Coder a redémarré avec succès.\n"));
936
+ break;
937
+
938
+ case '/version':
939
+ console.log(chalk.cyan(`Version de Cypher Coder: 1.0.0 (Mode Hybride local/Space)`));
940
+ break;
941
+
942
+ case '/about':
943
+ console.log(chalk.cyan(`\n=== À propos de Cypher Coder ===`));
944
+ console.log(`Nom : ${APP_NAME}`);
945
+ console.log(`Créateur : ${AUTHOR} (Étudiant IUD)`);
946
+ console.log(`Description: Assistant IA autonome de codage local et réseau.`);
947
+ console.log(`Modèle : Qwen/Qwen2.5-Coder-32B-Instruct`);
948
+ console.log(`Réseau : FastAPI + Gradio (Docker Space HF)\n`);
949
+ break;
950
+
951
+ case '/status':
952
+ const dirContext = getCurrentDirectoryContext();
953
+ console.log(chalk.yellow("\n=== Statut de la Session ==="));
954
+ console.log(` Dossier de travail : ${chalk.cyan(path.resolve("."))}`);
955
+ console.log(` Backend Space : ${chalk.cyan("https://theshellmaster-cypher-coder.hf.space")}`);
956
+ console.log(` Modèle utilisé : ${chalk.cyan(sessionConfig.model)}`);
957
+ console.log(` Température : ${chalk.cyan(sessionConfig.temperature)}`);
958
+ console.log(` Max Tokens : ${chalk.cyan(sessionConfig.max_tokens)}`);
959
+ console.log(` Auteur : ${chalk.cyan(AUTHOR)}`);
960
+ console.log(` Fichiers suivis : ${chalk.dim(dirContext)}\n`);
961
+ break;
962
+
963
+ // --- 2. Gestion du contexte & mémoire
964
+ case '/context':
965
+ if (cleanArgs[0] === 'clear') {
966
+ loadedFiles = [];
967
+ console.log(chalk.green("Contexte de fichiers vidé."));
968
+ } else if (cleanArgs[0] === 'save') {
969
+ const name = cleanArgs[1];
970
+ if (!name) {
971
+ console.log(chalk.red("Erreur: Spécifiez un nom. Exemple: /context save ma_session"));
972
+ } else {
973
+ savedContexts[name] = JSON.stringify(chatMessages);
974
+ console.log(chalk.green(`Contexte sauvegardé sous le nom '${name}'.`));
975
+ }
976
+ } else if (cleanArgs[0] === 'load') {
977
+ const name = cleanArgs[1];
978
+ if (!name || !savedContexts[name]) {
979
+ console.log(chalk.red(`Erreur: Contexte '${name}' introuvable.`));
980
+ } else {
981
+ chatMessages = JSON.parse(savedContexts[name]);
982
+ console.log(chalk.green(`Contexte '${name}' restauré avec succès.`));
983
+ }
984
+ } else if (cleanArgs[0] === 'list') {
985
+ console.log(chalk.yellow("Contextes sauvegardés :"), Object.keys(savedContexts));
986
+ } else {
987
+ console.log(chalk.yellow("Fichiers chargés en contexte local :"));
988
+ if (loadedFiles.length === 0) console.log(" Aucun fichier chargé.");
989
+ loadedFiles.forEach(f => console.log(` - ${f}`));
990
+ }
991
+ break;
992
+
993
+ case '/memory':
994
+ if (cleanArgs[0] === 'clear') {
995
+ initChat();
996
+ console.log(chalk.green("Mémoire système réinitialisée."));
997
+ } else {
998
+ console.log(chalk.yellow("\n=== Mémoire de session active ==="));
999
+ console.log(`Nombre de messages stockés : ${chatMessages.length}`);
1000
+ console.log("System Prompt actif :");
1001
+ console.log(chalk.dim(chatMessages[0]?.content || "Aucun"));
1002
+ console.log("===================================\n");
1003
+ }
1004
+ break;
1005
+
1006
+ case '/tokens':
1007
+ const textLength = JSON.stringify(chatMessages).length;
1008
+ const estTokens = Math.round(textLength / 4);
1009
+ console.log(chalk.cyan(`Statistiques de tokens (estimations) :`));
1010
+ console.log(` Utilisés (contexte actuel) : ~${estTokens} tokens`);
1011
+ console.log(` Max configuré par réponse : ${sessionConfig.max_tokens} tokens`);
1012
+ break;
1013
+
1014
+ // --- 3. Historique
1015
+ case '/history':
1016
+ if (cleanArgs[0] === 'clear') {
1017
+ commandHistory = [];
1018
+ console.log(chalk.green("Historique des commandes vidé."));
1019
+ } else if (cleanArgs[0] === 'save') {
1020
+ const file = cleanArgs[1] || 'history_export.json';
1021
+ fs.writeFileSync(file, JSON.stringify(commandHistory, null, 2), 'utf8');
1022
+ console.log(chalk.green(`Historique exporté dans : ${file}`));
1023
+ } else if (cleanArgs[0] === 'load') {
1024
+ const file = cleanArgs[1];
1025
+ if (file && fs.existsSync(file)) {
1026
+ commandHistory = JSON.parse(fs.readFileSync(file, 'utf8'));
1027
+ console.log(chalk.green(`Historique importé depuis ${file}.`));
1028
+ } else {
1029
+ console.log(chalk.red("Fichier introuvable."));
1030
+ }
1031
+ } else if (cleanArgs[0] === 'search') {
1032
+ const query = cleanArgs.slice(1).join(' ').toLowerCase();
1033
+ const matches = commandHistory.filter(h => h.toLowerCase().includes(query));
1034
+ console.log(chalk.yellow(`Correspondances trouvées (${matches.length}) :`));
1035
+ matches.forEach(m => console.log(` ${m}`));
1036
+ } else {
1037
+ console.log(chalk.yellow("\n=== Historique des commandes utilisateur ==="));
1038
+ commandHistory.forEach((c, idx) => console.log(` ${idx + 1}. ${c}`));
1039
+ console.log("=============================================\n");
1040
+ }
1041
+ break;
1042
+
1043
+ case '/last':
1044
+ if (!lastAssistantResponse) {
1045
+ console.log(chalk.yellow("Aucune réponse précédente disponible."));
1046
+ } else {
1047
+ console.log(chalk.green("\n🤖 Dernière réponse de Cypher :"));
1048
+ console.log(marked(lastAssistantResponse));
1049
+ }
1050
+ break;
1051
+
1052
+ case '/redo':
1053
+ let lastUserText = "";
1054
+ for (let i = chatMessages.length - 1; i >= 0; i--) {
1055
+ if (chatMessages[i].role === 'user' && !chatMessages[i].content.startsWith('/')) {
1056
+ lastUserText = chatMessages[i].content;
1057
+ break;
1058
+ }
1059
+ }
1060
+ if (lastUserText) {
1061
+ console.log(chalk.cyan(`Relance de la requête : "${lastUserText}"`));
1062
+ chatMessages.push({"role": "user", "content": lastUserText});
1063
+ await runAgentTurn();
1064
+ } else {
1065
+ console.log(chalk.yellow("Aucune requête textuelle trouvée à relancer."));
1066
+ }
1067
+ break;
1068
+
1069
+ case '/undo':
1070
+ if (chatMessages.length > 2) {
1071
+ chatMessages.pop();
1072
+ chatMessages.pop();
1073
+ console.log(chalk.green("Dernière interaction utilisateur/assistant annulée du contexte."));
1074
+ } else {
1075
+ console.log(chalk.yellow("Rien à annuler."));
1076
+ }
1077
+ break;
1078
+
1079
+ // --- 4. Gestion du modèle LLM
1080
+ case '/model':
1081
+ if (cleanArgs[0] === 'list') {
1082
+ console.log(chalk.cyan("Modèles disponibles via Hugging Face Inference :"));
1083
+ console.log(" - Qwen/Qwen2.5-Coder-32B-Instruct (Recommandé - Actif par défaut)");
1084
+ console.log(" - meta-llama/Llama-3.3-70B-Instruct");
1085
+ console.log(" - deepseek-ai/DeepSeek-Coder-V2-Instruct");
1086
+ } else if (cleanArgs[0] === 'set') {
1087
+ const newModel = cleanArgs[1];
1088
+ if (!newModel) {
1089
+ console.log(chalk.red("Usage: /model set <nom_du_modèle>"));
1090
+ } else {
1091
+ sessionConfig.model = newModel;
1092
+ console.log(chalk.green(`Modèle modifié vers : ${newModel}`));
1093
+ }
1094
+ } else if (cleanArgs[0] === 'info') {
1095
+ console.log(chalk.cyan(`\n=== Infos sur le modèle actif ===`));
1096
+ console.log(`Nom: ${sessionConfig.model}`);
1097
+ console.log(`Type: Coder/Instruct LLM`);
1098
+ console.log(`Capacités: Génération de code, Tool calling, Recherche web`);
1099
+ console.log(`Limites recommandées: 2048 tokens max par génération.`);
1100
+ } else {
1101
+ console.log(chalk.cyan(`Modèle actif : ${sessionConfig.model}`));
1102
+ }
1103
+ break;
1104
+
1105
+ case '/temperature':
1106
+ const tempVal = parseFloat(cleanArgs[0]);
1107
+ if (isNaN(tempVal) || tempVal < 0 || tempVal > 1) {
1108
+ console.log(chalk.red("Usage: /temperature <valeur entre 0.0 et 1.0> (actuelle: " + sessionConfig.temperature + ")"));
1109
+ } else {
1110
+ sessionConfig.temperature = tempVal;
1111
+ console.log(chalk.green(`Température mise à jour : ${tempVal}`));
1112
+ }
1113
+ break;
1114
+
1115
+ case '/top_p':
1116
+ const topPVal = parseFloat(cleanArgs[0]);
1117
+ if (isNaN(topPVal) || topPVal < 0 || topPVal > 1) {
1118
+ console.log(chalk.red("Usage: /top_p <valeur entre 0.0 et 1.0> (actuel: " + sessionConfig.top_p + ")"));
1119
+ } else {
1120
+ sessionConfig.top_p = topPVal;
1121
+ console.log(chalk.green(`Top_p mis à jour : ${topPVal}`));
1122
+ }
1123
+ break;
1124
+
1125
+ case '/max_tokens':
1126
+ const maxT = parseInt(cleanArgs[0], 10);
1127
+ if (isNaN(maxT) || maxT <= 0) {
1128
+ console.log(chalk.red("Usage: /max_tokens <nombre> (actuel: " + sessionConfig.max_tokens + ")"));
1129
+ } else {
1130
+ sessionConfig.max_tokens = maxT;
1131
+ console.log(chalk.green(`Max tokens mis à jour : ${maxT}`));
1132
+ }
1133
+ break;
1134
+
1135
+ case '/system':
1136
+ if (cleanArgs[0] === 'set') {
1137
+ const newSys = cleanArgs.slice(1).join(' ');
1138
+ chatMessages[0] = { role: 'system', content: newSys };
1139
+ console.log(chalk.green("Prompt système modifié."));
1140
+ } else if (cleanArgs[0] === 'reset') {
1141
+ chatMessages[0] = { role: 'system', content: getSystemPrompt() };
1142
+ console.log(chalk.green("Prompt système réinitialisé aux valeurs par défaut."));
1143
+ } else {
1144
+ console.log(chalk.cyan("Prompt système actif :"));
1145
+ console.log(chalk.dim(chatMessages[0]?.content));
1146
+ }
1147
+ break;
1148
+
1149
+ case '/stream':
1150
+ if (cleanArgs[0] === 'on') {
1151
+ sessionConfig.stream = true;
1152
+ console.log(chalk.green("Streaming activé (simulé)."));
1153
+ } else {
1154
+ sessionConfig.stream = false;
1155
+ console.log(chalk.green("Streaming désactivé."));
1156
+ }
1157
+ break;
1158
+
1159
+ // --- 5. Gestion de fichiers
1160
+ case '/file':
1161
+ if (cleanArgs[0] === 'load') {
1162
+ const fpath = cleanArgs[1];
1163
+ if (fpath && fs.existsSync(fpath)) {
1164
+ loadedFiles.push(path.resolve(fpath));
1165
+ console.log(chalk.green(`Fichier chargé dans le contexte : ${fpath}`));
1166
+ } else {
1167
+ console.log(chalk.red("Fichier introuvable."));
1168
+ }
1169
+ } else if (cleanArgs[0] === 'read') {
1170
+ const fpath = cleanArgs[1];
1171
+ if (fpath && fs.existsSync(fpath)) {
1172
+ console.log(chalk.cyan(`Contenu de ${fpath} :`));
1173
+ console.log(fs.readFileSync(fpath, 'utf8'));
1174
+ } else {
1175
+ console.log(chalk.red("Fichier introuvable."));
1176
+ }
1177
+ } else if (cleanArgs[0] === 'write') {
1178
+ const fpath = cleanArgs[1];
1179
+ if (!fpath) {
1180
+ console.log(chalk.red("Usage: /file write <chemin>"));
1181
+ } else if (!lastAssistantResponse) {
1182
+ console.log(chalk.red("Aucune réponse disponible à enregistrer."));
1183
+ } else {
1184
+ fs.writeFileSync(fpath, lastAssistantResponse, 'utf8');
1185
+ console.log(chalk.green(`Dernière réponse enregistrée dans ${fpath}`));
1186
+ }
1187
+ } else if (cleanArgs[0] === 'append') {
1188
+ const fpath = cleanArgs[1];
1189
+ if (!fpath) {
1190
+ console.log(chalk.red("Usage: /file append <chemin>"));
1191
+ } else if (!lastAssistantResponse) {
1192
+ console.log(chalk.red("Aucune réponse disponible à enregistrer."));
1193
+ } else {
1194
+ fs.appendFileSync(fpath, "\n" + lastAssistantResponse, 'utf8');
1195
+ console.log(chalk.green(`Dernière réponse ajoutée à la fin de ${fpath}`));
1196
+ }
1197
+ } else if (cleanArgs[0] === 'list') {
1198
+ console.log(chalk.yellow("Fichiers suivis :"), loadedFiles);
1199
+ } else if (cleanArgs[0] === 'clear') {
1200
+ loadedFiles = [];
1201
+ console.log(chalk.green("Fichiers déchargés du contexte."));
1202
+ } else if (cleanArgs[0] === 'diff') {
1203
+ const f1 = cleanArgs[1];
1204
+ const f2 = cleanArgs[2];
1205
+ if (f1 && f2 && fs.existsSync(f1) && fs.existsSync(f2)) {
1206
+ console.log(chalk.yellow(`--- Comparaison de ${f1} et ${f2} ---`));
1207
+ try {
1208
+ const out = execSync(`diff -u ${f1} ${f2}`).toString();
1209
+ console.log(out || "Aucune différence.");
1210
+ } catch (e) {
1211
+ console.log(e.stdout ? e.stdout.toString() : e.message);
1212
+ }
1213
+ } else {
1214
+ console.log(chalk.red("Erreur: Spécifiez deux fichiers valides."));
1215
+ }
1216
+ }
1217
+ break;
1218
+
1219
+ case '/upload':
1220
+ console.log(chalk.green(`Fichier ${cleanArgs[0]} simulé comme uploadé.`));
1221
+ break;
1222
+ case '/download':
1223
+ console.log(chalk.green(`Fichier ${cleanArgs[0]} simulé comme téléchargé.`));
1224
+ break;
1225
+
1226
+ // --- 6. Exécution de code
1227
+ case '/run':
1228
+ if (cleanArgs.length === 0) {
1229
+ if (!lastAssistantResponse) {
1230
+ console.log(chalk.red("Aucun code généré précédemment."));
1231
+ } else {
1232
+ const blockRegex = /```(javascript|js|python|py|bash|sh)?\n([\s\S]*?)```/;
1233
+ const match = lastAssistantResponse.match(blockRegex);
1234
+ if (match) {
1235
+ const lang = match[1] || 'js';
1236
+ const code = match[2];
1237
+ console.log(chalk.yellow(`Exécution du bloc de code détecté (${lang})...`));
1238
+ await executeLocalCode(lang, code);
1239
+ } else {
1240
+ console.log(chalk.red("Aucun bloc de code markdown trouvé."));
1241
+ }
1242
+ }
1243
+ } else {
1244
+ const lang = cleanArgs[0];
1245
+ const code = cleanArgs.slice(1).join(' ');
1246
+ await executeLocalCode(lang, code);
1247
+ }
1248
+ break;
1249
+
1250
+ case '/exec':
1251
+ const cmd = cleanArgs.join(' ');
1252
+ if (!cmd) {
1253
+ console.log(chalk.red("Spécifiez une commande à exécuter."));
1254
+ } else {
1255
+ console.log(chalk.cyan(`Exécution de la commande : ${cmd}`));
1256
+ await handleToolExecution('run_command', { command: cmd });
1257
+ }
1258
+ break;
1259
+
1260
+ case '/shell':
1261
+ console.log(chalk.yellow("Lancement du terminal interactif (tapez 'exit' pour quitter le sous-shell)..."));
1262
+ try {
1263
+ execSync('bash', { stdio: 'inherit' });
1264
+ } catch (e) {}
1265
+ break;
1266
+
1267
+ case '/repl':
1268
+ const rlang = cleanArgs[0] || 'node';
1269
+ console.log(chalk.yellow(`Lancement du REPL ${rlang}...`));
1270
+ try {
1271
+ execSync(rlang, { stdio: 'inherit' });
1272
+ } catch (e) {}
1273
+ break;
1274
+
1275
+ case '/eval':
1276
+ const expr = cleanArgs.join(' ');
1277
+ try {
1278
+ const res = eval(expr);
1279
+ console.log(chalk.green(`Résultat : ${res}`));
1280
+ } catch (e) {
1281
+ console.log(chalk.red(`Erreur d'évaluation : ${e.message}`));
1282
+ }
1283
+ break;
1284
+
1285
+ case '/sandbox':
1286
+ if (cleanArgs[0] === 'on') {
1287
+ sessionConfig.sandbox = true;
1288
+ console.log(chalk.green("Bac à sable activé (simulé)."));
1289
+ } else {
1290
+ sessionConfig.sandbox = false;
1291
+ console.log(chalk.green("Bac à sable désactivé."));
1292
+ }
1293
+ break;
1294
+
1295
+ case '/output':
1296
+ if (cleanArgs[0] === 'clear') {
1297
+ console.log(chalk.green("Sortie nettoyée."));
1298
+ } else {
1299
+ console.log(chalk.gray("Aucune sortie récente enregistrée en dehors du terminal."));
1300
+ }
1301
+ break;
1302
+
1303
+ // --- 7. Plugins & outils
1304
+ case '/tools':
1305
+ console.log(chalk.cyan("Outils d'interaction locaux disponibles :"));
1306
+ tools.forEach(t => console.log(` - ${t.function.name} : ${t.function.description}`));
1307
+ break;
1308
+
1309
+ case '/tool':
1310
+ if (cleanArgs[0] === 'info') {
1311
+ const name = cleanArgs[1];
1312
+ const tool = tools.find(t => t.function.name === name);
1313
+ if (tool) {
1314
+ console.log(chalk.cyan(`Outil [${name}] :`), tool.function.description);
1315
+ } else {
1316
+ console.log(chalk.red("Outil introuvable."));
1317
+ }
1318
+ } else {
1319
+ console.log(chalk.yellow("Les outils fondamentaux de Cypher Coder sont activés par défaut pour assurer son autonomie."));
1320
+ }
1321
+ break;
1322
+
1323
+ case '/plugin':
1324
+ console.log(chalk.cyan("Aucun plugin externe installé."));
1325
+ break;
1326
+
1327
+ case '/web':
1328
+ if (cleanArgs[0] === 'search') {
1329
+ const q = cleanArgs.slice(1).join(' ');
1330
+ console.log(chalk.cyan(`Recherche en ligne pour : "${q}"`));
1331
+ const res = callApiViaCurl([
1332
+ { role: "system", content: "Fais une recherche web et renvoie les résultats." },
1333
+ { role: "user", content: q }
1334
+ ], []);
1335
+ console.log(res.content);
1336
+ } else if (cleanArgs[0] === 'fetch') {
1337
+ const url = cleanArgs[1];
1338
+ console.log(chalk.cyan(`Récupération de l'URL : ${url}...`));
1339
+ const res = callApiViaCurl([
1340
+ { role: "system", content: "Récupère le contenu de cette URL et synthétise-la." },
1341
+ { role: "user", content: url }
1342
+ ], []);
1343
+ console.log(res.content);
1344
+ }
1345
+ break;
1346
+
1347
+ // --- 8. Affichage & formatting
1348
+ case '/theme':
1349
+ if (cleanArgs[0] === 'list') {
1350
+ console.log("Thèmes : dark (par défaut), light");
1351
+ } else if (cleanArgs[0] === 'light') {
1352
+ sessionConfig.theme = 'light';
1353
+ console.log(chalk.green("Thème light configuré."));
1354
+ } else {
1355
+ sessionConfig.theme = 'dark';
1356
+ console.log(chalk.green("Thème dark configuré."));
1357
+ }
1358
+ break;
1359
+
1360
+ case '/format':
1361
+ const fmt = cleanArgs[0];
1362
+ if (['md', 'plain', 'json'].includes(fmt)) {
1363
+ sessionConfig.format = fmt;
1364
+ console.log(chalk.green(`Format des réponses : ${fmt}`));
1365
+ } else {
1366
+ console.log(chalk.red("Formats valides : md, plain, json"));
1367
+ }
1368
+ break;
1369
+
1370
+ case '/wrap':
1371
+ case '/verbose':
1372
+ case '/silent':
1373
+ case '/color':
1374
+ const setting = commandName.slice(1);
1375
+ if (cleanArgs[0] === 'on' || cleanArgs[0] === 'true') {
1376
+ sessionConfig[setting] = true;
1377
+ console.log(chalk.green(`Option ${setting} activée.`));
1378
+ } else {
1379
+ sessionConfig[setting] = false;
1380
+ console.log(chalk.green(`Option ${setting} désactivée.`));
1381
+ }
1382
+ break;
1383
+
1384
+ case '/lang':
1385
+ sessionConfig.lang = cleanArgs[0] || 'fr';
1386
+ console.log(chalk.green(`Langue configurée : ${sessionConfig.lang}`));
1387
+ break;
1388
+
1389
+ case '/font':
1390
+ console.log(chalk.gray("Option disponible sur terminaux compatibles uniquement."));
1391
+ break;
1392
+
1393
+ // --- 9. Config & credentials
1394
+ case '/config':
1395
+ if (cleanArgs[0] === 'set') {
1396
+ const key = cleanArgs[1];
1397
+ const val = cleanArgs[2];
1398
+ if (key in sessionConfig) {
1399
+ sessionConfig[key] = val;
1400
+ console.log(chalk.green(`Configuration ${key} mise à jour.`));
1401
+ } else {
1402
+ console.log(chalk.red("Clé introuvable."));
1403
+ }
1404
+ } else if (cleanArgs[0] === 'reset') {
1405
+ sessionConfig.model = "Qwen/Qwen2.5-Coder-32B-Instruct";
1406
+ sessionConfig.temperature = 0.7;
1407
+ sessionConfig.max_tokens = 2048;
1408
+ console.log(chalk.green("Configuration réinitialisée."));
1409
+ } else {
1410
+ console.log(chalk.cyan("Configuration en cours :"), sessionConfig);
1411
+ }
1412
+ break;
1413
+
1414
+ case '/api':
1415
+ console.log(chalk.green("Authentification gérée via variable d'environnement HF_TOKEN ou secret d'Espace."));
1416
+ break;
1417
+
1418
+ case '/env':
1419
+ if (cleanArgs[0] === 'set') {
1420
+ const key = cleanArgs[1];
1421
+ const val = cleanArgs[2];
1422
+ sessionConfig.env[key] = val;
1423
+ console.log(chalk.green(`Variable d'environnement locale définie: ${key}=${val}`));
1424
+ } else {
1425
+ console.log(chalk.cyan("Variables d'environnement de l'agent :"), sessionConfig.env);
1426
+ }
1427
+ break;
1428
+
1429
+ // --- 10. Monitoring & debug
1430
+ case '/debug':
1431
+ if (cleanArgs[0] === 'on') {
1432
+ sessionConfig.verbose = true;
1433
+ console.log(chalk.green("Mode debug/verbose activé."));
1434
+ } else {
1435
+ sessionConfig.verbose = false;
1436
+ console.log(chalk.green("Mode debug/verbose désactivé."));
1437
+ }
1438
+ break;
1439
+
1440
+ case '/log':
1441
+ if (cleanArgs[0] === 'clear') {
1442
+ logs = [];
1443
+ console.log(chalk.green("Logs locaux effacés."));
1444
+ } else if (cleanArgs[0] === 'save') {
1445
+ const file = cleanArgs[1] || 'cypher_agent.log';
1446
+ fs.writeFileSync(file, logs.join('\n'), 'utf8');
1447
+ console.log(chalk.green(`Logs exportés dans ${file}`));
1448
+ } else {
1449
+ console.log(chalk.yellow("\n=== Logs récents de l'agent ==="));
1450
+ logs.slice(-20).forEach(l => console.log(l));
1451
+ console.log("===============================\n");
1452
+ }
1453
+ break;
1454
+
1455
+ case '/benchmark':
1456
+ console.log(chalk.cyan("Lancement du benchmark de l'API Hugging Face..."));
1457
+ const start = Date.now();
1458
+ try {
1459
+ callApiViaCurl([{ role: "user", content: "Dis hello" }], []);
1460
+ console.log(chalk.green(`Réussi ! Temps de latence aller-retour : ${Date.now() - start}ms`));
1461
+ } catch (e) {
1462
+ console.log(chalk.red(`Échec du benchmark : ${e.message}`));
1463
+ }
1464
+ break;
1465
+
1466
+ case '/ping':
1467
+ console.log(chalk.cyan("Ping de la passerelle API..."));
1468
+ try {
1469
+ const startPing = Date.now();
1470
+ execSync("curl -sI https://theshellmaster-cypher-coder.hf.space/ | head -n 1");
1471
+ console.log(chalk.green(`Connectivité OK (${Date.now() - startPing}ms)`));
1472
+ } catch (e) {
1473
+ console.log(chalk.red("Erreur de connexion."));
1474
+ }
1475
+ break;
1476
+
1477
+ case '/stats':
1478
+ console.log(chalk.cyan(`\n=== Statistiques de la session ===`));
1479
+ console.log(` Messages dans la conversation : ${chatMessages.length}`);
1480
+ console.log(` Fichiers chargés en contexte : ${loadedFiles.length}`);
1481
+ console.log(` Commandes tapées : ${commandHistory.length}`);
1482
+ console.log(` Nombre d'événements loggués : ${logs.length}\n`);
1483
+ break;
1484
+
1485
+ case '/trace':
1486
+ console.log(chalk.cyan("Dernier appel :"), logs[logs.length - 1] || "Aucun appel tracé.");
1487
+ break;
1488
+
1489
+ case '/inspect':
1490
+ const vname = cleanArgs[0];
1491
+ if (vname === 'chatMessages') console.log(chatMessages);
1492
+ else if (vname === 'loadedFiles') console.log(loadedFiles);
1493
+ else console.log(sessionConfig);
1494
+ break;
1495
+
1496
+ // --- 11. Automatisation & scripting
1497
+ case '/macro':
1498
+ if (cleanArgs[0] === 'save') {
1499
+ const name = cleanArgs[1];
1500
+ macros[name] = [...commandHistory];
1501
+ console.log(chalk.green(`Historique des commandes sauvegardé dans la macro '${name}'.`));
1502
+ } else if (cleanArgs[0] === 'run') {
1503
+ const name = cleanArgs[1];
1504
+ if (macros[name]) {
1505
+ console.log(chalk.yellow(`Exécution de la macro : ${name}`));
1506
+ for (const cmd of macros[name]) {
1507
+ if (!cmd.startsWith('/macro')) {
1508
+ await handleSlashCommand(cmd);
1509
+ }
1510
+ }
1511
+ } else {
1512
+ console.log(chalk.red("Macro introuvable."));
1513
+ }
1514
+ } else if (cleanArgs[0] === 'list') {
1515
+ console.log(chalk.cyan("Macros disponibles :"), Object.keys(macros));
1516
+ } else if (cleanArgs[0] === 'delete') {
1517
+ delete macros[cleanArgs[1]];
1518
+ console.log(chalk.green(`Macro '${cleanArgs[1]}' supprimée.`));
1519
+ }
1520
+ break;
1521
+
1522
+ case '/pipe':
1523
+ console.log(chalk.yellow("Chaînage d'outils simulé."));
1524
+ break;
1525
+
1526
+ case '/loop':
1527
+ const times = parseInt(cleanArgs[0], 10);
1528
+ const cmdToLoop = cleanArgs.slice(1).join(' ');
1529
+ if (!isNaN(times) && cmdToLoop) {
1530
+ for (let idx = 0; idx < times; idx++) {
1531
+ console.log(chalk.cyan(`[Boucle ${idx+1}/${times}] Exécution...`));
1532
+ await handleSlashCommand(cmdToLoop);
1533
+ }
1534
+ }
1535
+ break;
1536
+
1537
+ case '/schedule':
1538
+ case '/watch':
1539
+ case '/batch':
1540
+ console.log(chalk.yellow("Fonctionnalité planifiée pour la prochaine version stable de Cypher Coder."));
1541
+ break;
1542
+
1543
+ default:
1544
+ console.log(chalk.red(`Commande slash inconnue: ${commandName}. Tapez /help pour afficher l'aide.`));
1545
+ break;
1546
+ }
1547
+
1548
+ return true;
1549
+ }
1550
+
1551
+ // Code runner helper
1552
+ async function executeLocalCode(lang, code) {
1553
+ let cmd = "";
1554
+ if (lang === 'javascript' || lang === 'js' || lang === 'node') {
1555
+ cmd = `node -e "${code.replace(/"/g, '\\"')}"`;
1556
+ } else if (lang === 'python' || lang === 'py' || lang === 'python3') {
1557
+ cmd = `python3 -c "${code.replace(/"/g, '\\"')}"`;
1558
+ } else if (lang === 'bash' || lang === 'sh') {
1559
+ cmd = code;
1560
+ } else {
1561
+ console.log(chalk.red(`Langage de code non pris en charge pour l'exécution automatique: ${lang}`));
1562
+ return;
1563
+ }
1564
+
1565
+ console.log(chalk.yellow(`Lancement du code local...`));
1566
+ await handleToolExecution('run_command', { command: cmd });
1567
+ }
1568
+
1569
  async function askQuestion() {
1570
  const { userInput } = await inquirer.prompt([
1571
  {
 
1582
  return askQuestion();
1583
  }
1584
 
1585
+ if (text.startsWith('/')) {
1586
+ const handled = await handleSlashCommand(text);
1587
+ if (handled) {
1588
+ return askQuestion();
1589
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1590
  }
1591
 
1592
+ lastUserInput = text;
1593
+ commandHistory.push(text);
 
 
 
 
 
 
 
 
1594
 
 
1595
  chatMessages.push({"role": "user", "content": text});
1596
  await runAgentTurn();
1597