Skip to content

Commit 40d443e

Browse files
committed
Add plugin and command manager features
Introduces a plugin guide, plugin manager modal, and command manager modal for enabling/disabling commands. Refactors app.js to support plugin loading, command toggling, and improved UI for command management. Adds new plugin example and updates styles for command toggles.
1 parent 83b9025 commit 40d443e

10 files changed

Lines changed: 4729 additions & 1113 deletions

File tree

PLUGIN_GUIDE.md

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
# Guide de Création de Plugins JavaScript pour Console Linux
2+
3+
## Méthodes d'Installation
4+
5+
### 1. Via le Dossier Plugins (Permanent)
6+
7+
Créez un dossier dans `plugins/` avec la structure suivante :
8+
9+
```
10+
plugins/
11+
└── mon-plugin/
12+
├── manifest.json
13+
├── index.js
14+
└── README.md (optionnel)
15+
```
16+
17+
### 2. Via Import Direct (Temporaire/Permanent)
18+
19+
Utilisez la commande `import-plugin` dans la console :
20+
21+
1. Tapez `import-plugin`
22+
2. Collez votre code JavaScript
23+
3. Tapez `END_PLUGIN` pour terminer
24+
4. Optionnel : `save-plugin <nom>` pour sauvegarder définitivement
25+
26+
## Structure d'un Plugin
27+
28+
Un plugin doit être organisé dans un dossier avec la structure suivante :
29+
30+
```
31+
plugins/
32+
└── mon-plugin/
33+
├── manifest.json
34+
├── index.js
35+
└── README.md (optionnel)
36+
```
37+
38+
## Fichier Manifest (manifest.json)
39+
40+
Le fichier `manifest.json` décrit votre plugin :
41+
42+
```json
43+
{
44+
"name": "Nom du Plugin",
45+
"version": "1.0.0",
46+
"description": "Description de votre plugin",
47+
"author": "Votre nom",
48+
"main": "index.js",
49+
"commands": ["commande1", "commande2"]
50+
}
51+
```
52+
53+
### Propriétés du Manifest
54+
55+
- **name** (requis) : Nom affiché du plugin
56+
- **version** (requis) : Version du plugin (format semver)
57+
- **description** (requis) : Description courte du plugin
58+
- **author** (requis) : Nom de l'auteur
59+
- **main** (requis) : Fichier principal à charger (généralement index.js)
60+
- **commands** (requis) : Liste des noms de commandes exportées
61+
62+
## Structure d'une Commande JavaScript
63+
64+
Chaque commande doit respecter cette structure :
65+
66+
```javascript
67+
const maCommande = {
68+
name: 'nom-commande', // Nom de la commande (requis)
69+
description: 'Description', // Description courte (requis)
70+
usage: 'usage exemple', // Exemple d'utilisation (requis)
71+
execute: (args) => { // Fonction d'exécution (requis)
72+
// args est un tableau des arguments
73+
return 'Résultat à afficher';
74+
},
75+
version: '1.0.0', // Version de la commande (optionnel)
76+
author: 'Auteur' // Auteur de la commande (optionnel)
77+
};
78+
```
79+
80+
### Fonction execute
81+
82+
- **Paramètre** : `args` - tableau des arguments passés à la commande
83+
- **Retour** :
84+
- String : texte à afficher dans la console
85+
- Promise<string> : pour les opérations asynchrones
86+
- undefined/null : n'affiche rien
87+
88+
## Exemple Complet
89+
90+
### manifest.json
91+
```json
92+
{
93+
"name": "Utilitaires Système",
94+
"version": "1.0.0",
95+
"description": "Commandes utiles pour le système",
96+
"author": "Communauté",
97+
"main": "index.js",
98+
"commands": ["sysinfo", "weather", "joke"]
99+
}
100+
```
101+
102+
### index.js
103+
```javascript
104+
const sysinfo = {
105+
name: 'sysinfo',
106+
description: 'Affiche les informations système',
107+
usage: 'sysinfo',
108+
execute: () => {
109+
const os = require('os');
110+
return `Système: ${os.type()} ${os.release()}\n` +
111+
`Architecture: ${os.arch()}\n` +
112+
`Mémoire libre: ${Math.round(os.freemem() / 1024 / 1024)} MB\n` +
113+
`Uptime: ${Math.round(os.uptime() / 60)} minutes`;
114+
}
115+
};
116+
117+
const weather = {
118+
name: 'weather',
119+
description: 'Affiche une météo fictive',
120+
usage: 'weather [ville]',
121+
execute: (args) => {
122+
const ville = args.length > 0 ? args.join(' ') : 'Paris';
123+
const temperatures = [15, 18, 22, 25, 28, 20, 16];
124+
const conditions = ['Ensoleillé', 'Nuageux', 'Pluvieux', 'Orageux'];
125+
126+
const temp = temperatures[Math.floor(Math.random() * temperatures.length)];
127+
const condition = conditions[Math.floor(Math.random() * conditions.length)];
128+
129+
return `Météo à ${ville}: ${temp}°C, ${condition} ☀️`;
130+
}
131+
};
132+
133+
const joke = {
134+
name: 'joke',
135+
description: 'Raconte une blague',
136+
usage: 'joke',
137+
execute: () => {
138+
const jokes = [
139+
"Pourquoi les plongeurs plongent-ils toujours en arrière ? Parce que sinon, ils tombent dans le bateau !",
140+
"Que dit un escargot quand il croise une limace ? 'Regarde, un nudiste !'",
141+
"Comment appelle-t-on un chat tombé dans un pot de peinture ? Un chat-mallow !",
142+
"Que dit un informaticien quand il se noie ? F1 ! F1 ! F1 !"
143+
];
144+
145+
return jokes[Math.floor(Math.random() * jokes.length)];
146+
}
147+
};
148+
149+
// Export des commandes
150+
module.exports = {
151+
sysinfo,
152+
weather,
153+
joke
154+
};
155+
```
156+
157+
## Exemple d'Import Direct
158+
159+
```javascript
160+
// Exemple de plugin simple à importer
161+
const hello = {
162+
name: 'hello',
163+
description: 'Dit bonjour',
164+
usage: 'hello [nom]',
165+
execute: (args) => {
166+
const name = args.join(' ') || 'monde';
167+
return `Hello ${name}!`;
168+
}
169+
};
170+
171+
const time = {
172+
name: 'time',
173+
description: 'Affiche l\'heure actuelle',
174+
usage: 'time',
175+
execute: () => {
176+
return `Il est ${new Date().toLocaleTimeString()}`;
177+
}
178+
};
179+
180+
module.exports = {
181+
hello,
182+
time
183+
};
184+
```
185+
186+
## Commandes du Système de Plugins
187+
188+
- `plugins` : Liste tous les plugins et commandes
189+
- `import-plugin` : Importer un plugin depuis du code
190+
- `save-plugin <nom>` : Sauvegarder un plugin temporaire
191+
- `remove-temp-plugin <nom>` : Supprimer un plugin temporaire
192+
193+
## Flux de Travail Recommandé
194+
195+
1. **Test rapide** : Utilisez `import-plugin` pour tester votre code
196+
2. **Validation** : Testez vos commandes
197+
3. **Sauvegarde** : Utilisez `save-plugin` si le plugin fonctionne bien
198+
4. **Partage** : Le plugin est maintenant dans le dossier `plugins/`
199+
200+
## Sécurité
201+
202+
Les plugins importés directement ont des restrictions :
203+
- ✅ Modules autorisés : `fs`, `path`, `os`, `crypto`, `util`
204+
- ❌ Modules interdits : `child_process`, `cluster`, etc.
205+
- ✅ Les plugins du dossier `plugins/` n'ont pas ces restrictions
206+
207+
- ⚠️ **Évitez `eval()`** sauf si absolument nécessaire et avec validation stricte
208+
-**Validez toujours les entrées utilisateur**
209+
-**Gérez les erreurs proprement**
210+
-**Limitez l'accès aux fichiers système sensibles**
211+
212+
## Débogage
213+
214+
Pour déboguer votre plugin :
215+
1. Ajoutez des `console.log()` dans votre fonction execute
216+
2. Vérifiez les erreurs dans la console
217+
3. Testez avec différents arguments
218+
219+
## Bonnes Pratiques JavaScript
220+
221+
### Validation des Arguments
222+
```javascript
223+
execute: (args) => {
224+
if (args.length === 0) {
225+
return 'Usage: ma-commande <argument>';
226+
}
227+
228+
const nombre = parseInt(args[0]);
229+
if (isNaN(nombre)) {
230+
return 'Erreur: L\'argument doit être un nombre';
231+
}
232+
233+
// Traitement...
234+
}
235+
```
236+
237+
### Gestion d'Erreurs
238+
```javascript
239+
execute: (args) => {
240+
try {
241+
// Code pouvant lever une erreur
242+
return resultat;
243+
} catch (error) {
244+
return `Erreur: ${error.message}`;
245+
}
246+
}
247+
```
248+
249+
### Commandes Asynchrones
250+
```javascript
251+
execute: async (args) => {
252+
try {
253+
const result = await maFonctionAsync();
254+
return `Résultat: ${result}`;
255+
} catch (error) {
256+
return `Erreur: ${error.message}`;
257+
}
258+
}
259+
```
260+
261+
### Utilisation de Modules Node.js
262+
```javascript
263+
const fs = require('fs');
264+
const path = require('path');
265+
const https = require('https');
266+
267+
const maCommande = {
268+
name: 'lire',
269+
description: 'Lit un fichier',
270+
usage: 'lire <fichier>',
271+
execute: (args) => {
272+
if (args.length === 0) {
273+
return 'Usage: lire <fichier>';
274+
}
275+
276+
try {
277+
const contenu = fs.readFileSync(args[0], 'utf8');
278+
return contenu;
279+
} catch (error) {
280+
return `Impossible de lire le fichier: ${error.message}`;
281+
}
282+
}
283+
};
284+
```

contents/css/styles.css

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,49 @@ body {
9797
background-color: #1f2937;
9898
}
9999

100+
/* Styles pour les toggles de commandes */
101+
.command-toggle {
102+
width: 48px;
103+
height: 24px;
104+
background-color: #374151;
105+
border-radius: 12px;
106+
position: relative;
107+
cursor: pointer;
108+
transition: all 0.3s ease;
109+
border: 1px solid #4b5563;
110+
display: flex;
111+
align-items: center;
112+
}
113+
114+
.command-toggle::before {
115+
content: '';
116+
position: absolute;
117+
top: 50%;
118+
left: 2px;
119+
width: 18px;
120+
height: 18px;
121+
background-color: #9ca3af;
122+
border-radius: 50%;
123+
transition: all 0.3s ease;
124+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
125+
}
126+
127+
.command-toggle.enabled {
128+
background-color: #10b981;
129+
border-color: #059669;
130+
}
131+
132+
.command-toggle.enabled::before {
133+
transform: translateX(26px) translateY(-50%);
134+
background-color: #ffffff;
135+
}
136+
137+
.command-toggle:hover {
138+
opacity: 0.8;
139+
transform: scale(1.05);
140+
}
141+
142+
.command-toggle:active {
143+
transform: scale(0.95);
144+
}
145+

0 commit comments

Comments
 (0)