create-byan-agent 2.58.1 → 2.59.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,90 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [2.59.1] - 2026-07-21
13
+
14
+ ### Added — app Desktop BYAN 1.0.0 : construite, empaquetee, prouvee
15
+ - L'app Electron (`app/`, produit "BYAN") est desormais construite et empaquetee
16
+ reellement. Preuve sur ce depot : `BYAN-1.0.0.AppImage` (108 Mo) et
17
+ `byan-app_1.0.0_amd64.deb` (74,6 Mo) produits par electron-builder ; le deb
18
+ installe `/opt/BYAN/byan` — le chemin exact que la detection du CLI
19
+ (`install/lib/desktop-app.js`) sonde pour ouvrir la fenetre native.
20
+ - Preuve d'execution du paquet (rejouable) : le serveur webui embarque, forke
21
+ exactement comme l'app le fait (NODE_PATH, PORT=0), repond ready + `/health`
22
+ 200 + `/api/status` 200 avec la detection rendue par le moteur d'install.
23
+ - Correctifs de lancement du paquet (revue adversariale : 1 block puis approve) :
24
+ - les ressources embarquees conservent la structure du depot
25
+ (`install/src/webui` + `install/lib` + `src/byan-v2/lib`) pour que les
26
+ require() relatifs resolvent a l'identique ;
27
+ - dependances du serveur declarees dans l'app et depaquetees en fichiers
28
+ reels (le fils forke n'a pas acces a l'archive asar) ;
29
+ - `.npmrc install-links=true` : la dependance locale byan-platform-config est
30
+ copiee, pas liee (electron-builder refuse un lien sortant de `app/`) ;
31
+ - `executableName: byan` cote Linux ; icone Windows regeneree en 256px ;
32
+ icone macOS convertie depuis le png au build (l'icns n'existe pas en depot).
33
+ - Release 3 OS : la chaine GitHub Actions existante construit
34
+ ubuntu/windows/macos et attache les artefacts a une release brouillon sur tag
35
+ `desktop-v*` (tag dedie — les tags `v*` portent les versions npm et ne
36
+ declenchent plus de release Desktop). Mode d'emploi dans `app/README.md`.
37
+
38
+ ### Fixed — serveur webui : le contrat PORT=0 est honore
39
+ - `install/src/webui/server.js` (expedie par npm) : `options.port ?? 3000` (0
40
+ est une valeur valide : le systeme assigne un port libre) et l'entree fork
41
+ lit desormais `PORT` et `BYAN_PROJECT_ROOT` d'environnement. L'usage CLI
42
+ (port explicite en argument) est inchange.
43
+
44
+ ## [2.59.0] - 2026-07-21
45
+
46
+ ### Fixed — assistant web : detection Claude/Codex reparee, interface en francais
47
+ - **Detection reparee.** L'ecran Detection affichait "not detected" pour Claude
48
+ Code et Codex sur une machine ou les deux sont installes (constat terrain,
49
+ Arch Linux). Cause : la route de statut interrogeait un detecteur qui cherchait
50
+ le fichier de config de Claude DESKTOP (l'app de chat,
51
+ `~/.config/Claude/claude_desktop_config.json`) et un dossier `.codex/prompts`
52
+ relatif au projet. La detection plateforme passe desormais par le moteur
53
+ d'installation (`detectEnvironment`) : `~/.claude` ou binaire `claude`,
54
+ `~/.codex` ou binaire `codex` — les faits machine, pas les artefacts d'une
55
+ autre application.
56
+ - **Interface en francais.** Les 7 etapes du wizard (accueil, detection, mode,
57
+ configuration, recapitulatif, installation, termine), la mise a jour et le
58
+ journal parlent francais (`lang="fr"`).
59
+
60
+ ### Changed — mode AUTO conforme au contrat
61
+ - Le mode AUTO ne baptise plus l'utilisateur "User" en anglais : il affiche une
62
+ configuration minimale qui demande **comment tu veux etre appele** (plus nom
63
+ et repertoire du projet, pre-remplis), puis va au recapitulatif.
64
+ - Defauts corriges : langue **Francais**, **tous les agents** (les 5 modules
65
+ core/bmm/bmb/tea/cis), plateformes = celles detectees sur la machine. Le
66
+ recapitulatif affiche "Agents : tous (roster complet)".
67
+ - Tests : `install/__tests__/webui-detection.test.js` (7 cas — cablage moteur de
68
+ la detection + garde-fous sur les defauts du front).
69
+
70
+ ### Docs — decision Electron vs Tauri
71
+ - Decision gravee dans `app/README.md` : Electron est conserve pour l'app
72
+ Desktop. Raison dominante : le serveur local est en Node ; Electron l'embarque
73
+ gratuitement, Tauri exigerait un Node annexe (qui annule son avantage de
74
+ taille) ou une reecriture du serveur. La coquille Electron existe deja
75
+ (main/preload/renderer, tests bout-en-bout, config de construction
76
+ Linux/Windows). A reevaluer seulement si le serveur quitte Node.
77
+
78
+ ## [2.58.2] - 2026-07-21
79
+
80
+ ### Fixed — l'assistant web plantait a l'ouverture (Cannot find module 'ws')
81
+ - Symptome : `create-byan-agent` (assistant web par defaut) plantait aussitot
82
+ avec `Error: Cannot find module 'ws'` depuis `install/src/webui/server.js`,
83
+ sur une installation globale `npm i -g`.
84
+ - Cause : `ws` (le serveur WebSocket de l'assistant) etait declare uniquement
85
+ dans `install/package.json` (interne, non publie). `npm` installe les
86
+ dependances du `package.json` RACINE ; `ws` en etait absent, donc introuvable
87
+ une fois le paquet installe.
88
+ - Correctif : `ws` (`^8.20.0`) ajoute aux dependances racine, la ou npm
89
+ l'installe reellement.
90
+ - Filet anti-regression : nouveau test `install/__tests__/shipped-deps.test.js`
91
+ qui scanne le code expedie (`install/bin`, `install/lib`, `install/src`) et
92
+ exige que chaque module externe require() soit declare dans les dependances
93
+ racine (ou soit un module natif Node). La derive "declare dans
94
+ install/package.json mais pas racine" echoue desormais au test.
95
+
12
96
  ## [2.58.1] - 2026-07-21
13
97
 
14
98
  ### Fixed — l'install auto en terminal gelait au controle des copies globales de skills
@@ -123,14 +123,35 @@ const routes = {
123
123
  if (detector) {
124
124
  try {
125
125
  detectionResult = await detector.detect();
126
- platforms = detectionResult.platforms
127
- .filter(p => p.detected)
128
- .map(p => p.name);
129
126
  } catch {
130
- // Fallback to fs-based detection
127
+ detectionResult = null;
131
128
  }
132
129
  }
133
130
 
131
+ // Platform detection (Claude Code / Codex) comes from the INSTALL ENGINE —
132
+ // the single source of truth. The yanstaller detector looked for Claude
133
+ // DESKTOP's config file (~/.config/Claude/claude_desktop_config.json) and
134
+ // for a project-local .codex/prompts dir, so a machine with the Claude Code
135
+ // CLI and Codex properly installed showed "not detected" (field bug,
136
+ // 2026-07-21, Arch Linux). The engine checks the real machine-level facts:
137
+ // ~/.claude or `command -v claude`, ~/.codex or `command -v codex`.
138
+ try {
139
+ const engineDetect = (server.installEngine || require('../../lib/install-engine')).detectEnvironment();
140
+ platforms = [
141
+ ...(engineDetect.claude ? ['claude'] : []),
142
+ ...(engineDetect.codex ? ['codex'] : []),
143
+ ];
144
+ const enginePlatforms = [
145
+ { name: 'claude', detected: engineDetect.claude },
146
+ { name: 'codex', detected: engineDetect.codex },
147
+ ];
148
+ detectionResult = detectionResult
149
+ ? { ...detectionResult, platforms: enginePlatforms }
150
+ : { platforms: enginePlatforms };
151
+ } catch {
152
+ // engine unavailable -> keep the project-local fs fallback computed above
153
+ }
154
+
134
155
  json(res, 200, {
135
156
  version,
136
157
  installed,
@@ -4,12 +4,14 @@ class ByanApp {
4
4
  this.stepHistory = [];
5
5
  this.ws = null;
6
6
  this.wsRetryDelay = 1000;
7
+ // Defauts valides : francais, tous les modules (l'installation AUTO pose
8
+ // tous les agents), plateformes remplies par la detection machine.
7
9
  this.config = {
8
10
  mode: 'auto',
9
11
  userName: '',
10
- language: 'English',
12
+ language: 'Francais',
11
13
  platforms: [],
12
- modules: ['core', 'bmm']
14
+ modules: ['core', 'bmm', 'bmb', 'tea', 'cis']
13
15
  };
14
16
  this.status = null;
15
17
  this.logCount = 0;
@@ -122,30 +124,30 @@ class ByanApp {
122
124
 
123
125
  let html = '';
124
126
 
125
- html += this.detectionRow(true, 'Node.js', this.status.detection?.nodeVersion || process.version || 'detected');
127
+ html += this.detectionRow(true, 'Node.js', this.status.detection?.nodeVersion || 'detecte');
126
128
  html += this.detectionRow(
127
129
  this.status.detection?.hasGit !== false,
128
130
  'Git',
129
- this.status.detection?.gitVersion || (this.status.detection?.hasGit !== false ? 'detected' : 'not found')
131
+ this.status.detection?.gitVersion || (this.status.detection?.hasGit !== false ? 'detecte' : 'introuvable')
130
132
  );
131
- html += this.detectionRow(true, 'Operating System', this.status.detection?.os || navigator.platform);
133
+ html += this.detectionRow(true, 'Systeme d\'exploitation', this.status.detection?.os || navigator.platform);
132
134
 
133
135
  const platformNames = { 'claude': 'Claude Code', 'codex': 'Codex' };
134
136
  const detectedPlatforms = this.status.detection?.platforms || [];
135
137
  if (detectedPlatforms.length > 0) {
136
138
  for (const p of detectedPlatforms) {
137
- html += this.detectionRow(p.detected, platformNames[p.name] || p.name, p.detected ? 'found' : 'not detected');
139
+ html += this.detectionRow(p.detected, platformNames[p.name] || p.name, p.detected ? 'detecte' : 'non detecte');
138
140
  }
139
141
  } else {
140
142
  for (const name of this.status.platforms || []) {
141
- html += this.detectionRow(true, platformNames[name] || name, 'found');
143
+ html += this.detectionRow(true, platformNames[name] || name, 'detecte');
142
144
  }
143
145
  }
144
146
 
145
147
  html += this.detectionRow(
146
148
  this.status.installed,
147
- 'Existing BYAN installation',
148
- this.status.installed ? 'found (will upgrade)' : 'clean install'
149
+ 'Installation BYAN existante',
150
+ this.status.installed ? 'trouvee (sera mise a jour)' : 'installation neuve'
149
151
  );
150
152
 
151
153
  container.innerHTML = html;
@@ -153,7 +155,7 @@ class ByanApp {
153
155
 
154
156
  this.config.platforms = this.status.platforms || [];
155
157
  } catch (err) {
156
- container.innerHTML = `<div class="detection-item"><div class="detection-status fail"></div><div class="detection-label">Detection failed</div><div class="detection-value">${this.escapeHtml(err.message)}</div></div>`;
158
+ container.innerHTML = `<div class="detection-item"><div class="detection-status fail"></div><div class="detection-label">Echec de la detection</div><div class="detection-value">${this.escapeHtml(err.message)}</div></div>`;
157
159
  nextBtn.disabled = false;
158
160
  }
159
161
  }
@@ -169,25 +171,25 @@ class ByanApp {
169
171
  document.querySelectorAll('.mode-cards .card').forEach(card => card.classList.remove('selected'));
170
172
  event.currentTarget.classList.add('selected');
171
173
 
174
+ // Le mode AUTO installe TOUS les agents (les 5 modules) sur les plateformes
175
+ // detectees, en francais — mais il demande quand meme le prenom : on ne
176
+ // baptise personne "User" d'office.
172
177
  if (mode === 'auto') {
173
- this.config.userName = this.status?.detection?.userName || 'User';
174
- this.config.language = 'English';
175
178
  this.config.modules = ['core', 'bmm', 'bmb', 'tea', 'cis'];
176
- this.showPreview();
177
- } else {
178
- this.showConfigForm(mode);
179
- this.showStep('config');
179
+ this.config.language = this.config.language || 'Francais';
180
180
  }
181
+ this.showConfigForm(mode);
182
+ this.showStep('config');
181
183
  }
182
184
 
183
185
  showConfigForm(mode) {
184
186
  const form = document.getElementById('config-form');
185
187
  const allModules = [
186
- { id: 'core', label: 'Core (foundation)', required: true },
187
- { id: 'bmm', label: 'BMM (software development)', required: false },
188
- { id: 'bmb', label: 'BMB (agent builder)', required: false },
189
- { id: 'tea', label: 'TEA (test architecture)', required: false },
190
- { id: 'cis', label: 'CIS (creative innovation)', required: false }
188
+ { id: 'core', label: 'Core (fondation)', required: true },
189
+ { id: 'bmm', label: 'BMM (developpement logiciel)', required: false },
190
+ { id: 'bmb', label: 'BMB (createur d\'agents)', required: false },
191
+ { id: 'tea', label: 'TEA (architecture de tests)', required: false },
192
+ { id: 'cis', label: 'CIS (innovation creative)', required: false }
191
193
  ];
192
194
 
193
195
  const platformOptions = [
@@ -197,42 +199,54 @@ class ByanApp {
197
199
 
198
200
  let html = `
199
201
  <div class="form-group">
200
- <label for="cfg-name">Your Name</label>
202
+ <label for="cfg-name">Comment veux-tu etre appele ?</label>
201
203
  <input id="cfg-name" type="text" value="${this.escapeHtml(this.config.userName)}" placeholder="Yan">
202
204
  </div>
203
205
  <div class="form-group">
204
- <label for="cfg-project-name">Project Name</label>
206
+ <label for="cfg-project-name">Nom du projet</label>
205
207
  <input id="cfg-project-name" type="text" value="${this.escapeHtml(this.config.projectName || '')}" placeholder="mon-projet">
206
208
  </div>
207
209
  <div class="form-group">
208
- <label for="cfg-project-dir">Project Directory</label>
210
+ <label for="cfg-project-dir">Repertoire du projet</label>
209
211
  <input id="cfg-project-dir" type="text" value="${this.escapeHtml(this.config.projectDir || this.status?.projectRoot || '')}" placeholder="/chemin/vers/le/projet">
210
- <div class="form-hint">Defaults to the directory the wizard was launched from.</div>
212
+ <div class="form-hint">Par defaut : le repertoire depuis lequel l'assistant a ete lance.</div>
211
213
  </div>
212
214
  <div class="form-group">
213
- <label for="cfg-lang">Communication Language</label>
215
+ <label for="cfg-lang">Langue de communication</label>
214
216
  <select id="cfg-lang">
215
- <option value="English" ${this.config.language === 'English' ? 'selected' : ''}>English</option>
216
217
  <option value="Francais" ${this.config.language === 'Francais' ? 'selected' : ''}>Francais</option>
218
+ <option value="English" ${this.config.language === 'English' ? 'selected' : ''}>English</option>
217
219
  </select>
218
- </div>
220
+ </div>`;
221
+
222
+ // En AUTO, plateformes et modules sont regles par la detection et le
223
+ // roster complet — pas de cases a cocher, juste l'essentiel.
224
+ if (mode === 'auto') {
225
+ const detected = (this.config.platforms || []).map(p => p === 'claude' ? 'Claude Code' : 'Codex').join(' + ') || 'aucune detectee';
226
+ html += `
219
227
  <div class="form-group">
220
- <label>Target Platforms</label>
221
- <div class="form-hint">Select the platforms you use.</div>
228
+ <div class="form-hint">Plateformes detectees : ${this.escapeHtml(detected)} &mdash; tous les agents seront installes.</div>
229
+ </div>`;
230
+ } else {
231
+ html += `
232
+ <div class="form-group">
233
+ <label>Plateformes cibles</label>
234
+ <div class="form-hint">Choisis les plateformes que tu utilises.</div>
222
235
  <div class="checkbox-group">`;
223
236
 
224
- for (const p of platformOptions) {
225
- const checked = this.config.platforms.includes(p.id) ? 'checked' : '';
226
- html += `<label><input type="checkbox" name="platform" value="${p.id}" ${checked}> ${this.escapeHtml(p.label)}</label>`;
227
- }
237
+ for (const p of platformOptions) {
238
+ const checked = this.config.platforms.includes(p.id) ? 'checked' : '';
239
+ html += `<label><input type="checkbox" name="platform" value="${p.id}" ${checked}> ${this.escapeHtml(p.label)}</label>`;
240
+ }
228
241
 
229
- html += `</div></div>`;
242
+ html += `</div></div>`;
243
+ }
230
244
 
231
245
  if (mode === 'manual') {
232
246
  html += `
233
247
  <div class="form-group">
234
248
  <label>Modules</label>
235
- <div class="form-hint">Core is always included.</div>
249
+ <div class="form-hint">Core est toujours inclus.</div>
236
250
  <div class="checkbox-group">`;
237
251
  for (const m of allModules) {
238
252
  const checked = m.required || this.config.modules.includes(m.id) ? 'checked' : '';
@@ -251,7 +265,7 @@ class ByanApp {
251
265
  const projNameEl = document.getElementById('cfg-project-name');
252
266
  const projDirEl = document.getElementById('cfg-project-dir');
253
267
 
254
- if (nameEl) this.config.userName = nameEl.value.trim() || 'User';
268
+ if (nameEl) this.config.userName = nameEl.value.trim() || 'Developpeur';
255
269
  if (langEl) this.config.language = langEl.value;
256
270
  if (projNameEl) this.config.projectName = projNameEl.value.trim();
257
271
  if (projDirEl) this.config.projectDir = projDirEl.value.trim();
@@ -271,14 +285,16 @@ class ByanApp {
271
285
  this.readConfigForm();
272
286
 
273
287
  const container = document.getElementById('preview-content');
288
+ const allModules = this.config.modules.length >= 5;
274
289
  const rows = [
275
290
  ['Mode', this.config.mode.toUpperCase()],
276
- ['User Name', this.config.userName || 'User'],
277
- ['Language', this.config.language],
278
- ['Platforms', this.config.platforms.join(', ') || 'auto-detect'],
291
+ ['Prenom', this.config.userName || 'Developpeur'],
292
+ ['Langue', this.config.language],
293
+ ['Plateformes', this.config.platforms.join(', ') || 'detection automatique'],
294
+ ['Agents', allModules ? 'tous (roster complet)' : `modules ${this.config.modules.join(', ')}`],
279
295
  ['Modules', this.config.modules.join(', ')],
280
- ['Project Name', this.config.projectName || '(nom du dossier)'],
281
- ['Project Root', this.config.projectDir || this.status?.projectRoot || '(auto)']
296
+ ['Nom du projet', this.config.projectName || '(nom du dossier)'],
297
+ ['Repertoire', this.config.projectDir || this.status?.projectRoot || '(auto)']
282
298
  ];
283
299
 
284
300
  container.innerHTML = rows.map(([k, v]) =>
@@ -290,7 +306,7 @@ class ByanApp {
290
306
 
291
307
  async confirmInstall() {
292
308
  this.showStep('progress');
293
- document.getElementById('progress-title').textContent = 'Installing...';
309
+ document.getElementById('progress-title').textContent = 'Installation en cours...';
294
310
  this.resetProgress();
295
311
 
296
312
  try {
@@ -301,7 +317,7 @@ class ByanApp {
301
317
  });
302
318
 
303
319
  if (!res.ok) {
304
- const err = await res.json().catch(() => ({ error: 'Unknown error' }));
320
+ const err = await res.json().catch(() => ({ error: 'Erreur inconnue' }));
305
321
  this.showComplete({ success: false, summary: { message: err.error } });
306
322
  }
307
323
  } catch (err) {
@@ -326,7 +342,7 @@ class ByanApp {
326
342
  container.innerHTML = `
327
343
  <div class="detection-item">
328
344
  <div class="detection-status ok"></div>
329
- <div class="detection-label">Update available</div>
345
+ <div class="detection-label">Mise a jour disponible</div>
330
346
  <div class="detection-value">${this.escapeHtml(data.installed)} &#8594; ${this.escapeHtml(data.latest)}</div>
331
347
  </div>
332
348
  ${data.changes.length > 0 ? '<div class="code-block">' + data.changes.map(c => this.escapeHtml(c)).join('\n') + '</div>' : ''}`;
@@ -335,23 +351,23 @@ class ByanApp {
335
351
  container.innerHTML = `
336
352
  <div class="detection-item">
337
353
  <div class="detection-status ok"></div>
338
- <div class="detection-label">Up to date</div>
354
+ <div class="detection-label">A jour</div>
339
355
  <div class="detection-value">v${this.escapeHtml(data.installed)}</div>
340
356
  </div>
341
- <p style="color:var(--text-muted);margin-top:1rem;">Your installation is already on the latest version.</p>`;
357
+ <p style="color:var(--text-muted);margin-top:1rem;">Ton installation est deja sur la derniere version.</p>`;
342
358
  confirmBtn.disabled = true;
343
359
  }
344
360
 
345
361
  actionsEl.style.display = 'flex';
346
362
  } catch (err) {
347
- container.innerHTML = `<div class="detection-item"><div class="detection-status fail"></div><div class="detection-label">Check failed</div><div class="detection-value">${this.escapeHtml(err.message)}</div></div>`;
363
+ container.innerHTML = `<div class="detection-item"><div class="detection-status fail"></div><div class="detection-label">Echec de la verification</div><div class="detection-value">${this.escapeHtml(err.message)}</div></div>`;
348
364
  actionsEl.style.display = 'flex';
349
365
  }
350
366
  }
351
367
 
352
368
  async confirmUpdate() {
353
369
  this.showStep('progress');
354
- document.getElementById('progress-title').textContent = 'Updating...';
370
+ document.getElementById('progress-title').textContent = 'Mise a jour en cours...';
355
371
  this.resetProgress();
356
372
 
357
373
  try {
@@ -362,7 +378,7 @@ class ByanApp {
362
378
  });
363
379
 
364
380
  if (!res.ok) {
365
- const err = await res.json().catch(() => ({ error: 'Unknown error' }));
381
+ const err = await res.json().catch(() => ({ error: 'Erreur inconnue' }));
366
382
  this.showComplete({ success: false, summary: { message: err.error } });
367
383
  }
368
384
  } catch (err) {
@@ -414,7 +430,7 @@ class ByanApp {
414
430
 
415
431
  resetProgress() {
416
432
  document.getElementById('progress-fill').style.width = '0%';
417
- document.getElementById('progress-label').textContent = 'Preparing...';
433
+ document.getElementById('progress-label').textContent = 'Preparation...';
418
434
  document.getElementById('progress-pct').textContent = '0%';
419
435
  }
420
436
 
@@ -426,22 +442,22 @@ class ByanApp {
426
442
  if (data.success) {
427
443
  icon.innerHTML = '&#10003;';
428
444
  icon.classList.remove('error');
429
- title.textContent = 'Installation Complete';
445
+ title.textContent = 'Installation terminee';
430
446
 
431
447
  const s = data.summary || {};
432
- let html = `<p>${this.escapeHtml(s.message || 'Done')}</p>`;
433
- if (s.projectRoot) html += `<p><strong>Project:</strong> <code>${this.escapeHtml(s.projectRoot)}</code></p>`;
434
- if (s.mode) html += `<p><strong>Mode:</strong> ${this.escapeHtml(s.mode)}</p>`;
435
- if (s.platforms && s.platforms.length) html += `<p><strong>Platforms:</strong> ${s.platforms.map(p => this.escapeHtml(p)).join(', ')}</p>`;
436
- html += '<p style="margin-top:1rem;color:var(--text-muted);">You can close this window.</p>';
448
+ let html = `<p>${this.escapeHtml(s.message || 'Termine')}</p>`;
449
+ if (s.projectRoot) html += `<p><strong>Projet :</strong> <code>${this.escapeHtml(s.projectRoot)}</code></p>`;
450
+ if (s.mode) html += `<p><strong>Mode :</strong> ${this.escapeHtml(s.mode)}</p>`;
451
+ if (s.platforms && s.platforms.length) html += `<p><strong>Plateformes :</strong> ${s.platforms.map(p => this.escapeHtml(p)).join(', ')}</p>`;
452
+ html += '<p style="margin-top:1rem;color:var(--text-muted);">Tu peux fermer cette fenetre.</p>';
437
453
  summary.innerHTML = html;
438
454
  } else {
439
455
  icon.innerHTML = '&#10007;';
440
456
  icon.classList.add('error');
441
- title.textContent = 'Installation Failed';
457
+ title.textContent = 'Echec de l\'installation';
442
458
 
443
- const msg = data.summary?.message || 'Unknown error';
444
- summary.innerHTML = `<p style="color:var(--error)">${this.escapeHtml(msg)}</p><p style="margin-top:1rem;color:var(--text-muted);">Check the logs below for details. You can try again.</p>`;
459
+ const msg = data.summary?.message || 'Erreur inconnue';
460
+ summary.innerHTML = `<p style="color:var(--error)">${this.escapeHtml(msg)}</p><p style="margin-top:1rem;color:var(--text-muted);">Consulte le journal ci-dessous pour le detail. Tu peux reessayer.</p>`;
445
461
  }
446
462
 
447
463
  this.showStep('done');
@@ -1,176 +1,176 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html lang="fr">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>BYAN - Agent Installer</title>
6
+ <title>BYAN - Assistant d'installation</title>
7
7
  <link rel="stylesheet" href="style.css">
8
8
  </head>
9
9
  <body>
10
10
  <header>
11
11
  <div class="header-inner">
12
12
  <h1 class="logo">BYAN</h1>
13
- <p class="subtitle">Builder of YAN &mdash; Agent Installer</p>
13
+ <p class="subtitle">Builder of YAN &mdash; Assistant d'installation</p>
14
14
  </div>
15
15
  </header>
16
16
 
17
- <nav class="wizard-steps" id="wizard-nav" aria-label="Installation steps">
17
+ <nav class="wizard-steps" id="wizard-nav" aria-label="Etapes d'installation">
18
18
  <ol>
19
- <li class="wizard-step active" data-step="welcome"><span class="step-num">1</span><span class="step-label">Welcome</span></li>
19
+ <li class="wizard-step active" data-step="welcome"><span class="step-num">1</span><span class="step-label">Accueil</span></li>
20
20
  <li class="wizard-step" data-step="detection"><span class="step-num">2</span><span class="step-label">Detection</span></li>
21
21
  <li class="wizard-step" data-step="mode"><span class="step-num">3</span><span class="step-label">Mode</span></li>
22
- <li class="wizard-step" data-step="config"><span class="step-num">4</span><span class="step-label">Config</span></li>
23
- <li class="wizard-step" data-step="preview"><span class="step-num">5</span><span class="step-label">Preview</span></li>
24
- <li class="wizard-step" data-step="progress"><span class="step-num">6</span><span class="step-label">Install</span></li>
25
- <li class="wizard-step" data-step="done"><span class="step-num">7</span><span class="step-label">Done</span></li>
22
+ <li class="wizard-step" data-step="config"><span class="step-num">4</span><span class="step-label">Configuration</span></li>
23
+ <li class="wizard-step" data-step="preview"><span class="step-num">5</span><span class="step-label">Recapitulatif</span></li>
24
+ <li class="wizard-step" data-step="progress"><span class="step-num">6</span><span class="step-label">Installation</span></li>
25
+ <li class="wizard-step" data-step="done"><span class="step-num">7</span><span class="step-label">Termine</span></li>
26
26
  </ol>
27
27
  </nav>
28
28
 
29
29
  <main>
30
- <!-- Step 1: Welcome -->
31
- <section class="step" id="step-welcome" role="region" aria-label="Welcome">
30
+ <!-- Etape 1 : Accueil -->
31
+ <section class="step" id="step-welcome" role="region" aria-label="Accueil">
32
32
  <div class="step-content">
33
- <h2>Welcome to BYAN</h2>
34
- <p class="lead">Intelligent AI agent platform with multi-platform support.<br>
35
- Claude Code and Codex.</p>
33
+ <h2>Bienvenue dans BYAN</h2>
34
+ <p class="lead">Plateforme d'agents IA intelligente, multi-plateforme.<br>
35
+ Claude Code et Codex.</p>
36
36
  <div class="feature-grid">
37
37
  <div class="feature-card">
38
38
  <div class="feature-icon" aria-hidden="true">&#9670;</div>
39
- <h3>64 Quality Mantras</h3>
40
- <p>Built on Merise Agile + TDD methodology with rigorous quality standards.</p>
39
+ <h3>71 mantras qualite</h3>
40
+ <p>Construit sur la methodologie Merise Agile + TDD avec des standards de qualite exigeants.</p>
41
41
  </div>
42
42
  <div class="feature-card">
43
43
  <div class="feature-icon" aria-hidden="true">&#9672;</div>
44
- <h3>Multi-Platform</h3>
45
- <p>Install agents across Claude Code and Codex simultaneously.</p>
44
+ <h3>Multi-plateforme</h3>
45
+ <p>Installe les agents sur Claude Code et Codex en meme temps.</p>
46
46
  </div>
47
47
  <div class="feature-card">
48
48
  <div class="feature-icon" aria-hidden="true">&#9656;</div>
49
- <h3>Smart Detection</h3>
50
- <p>Automatically detects your environment and recommends optimal configuration.</p>
49
+ <h3>Detection intelligente</h3>
50
+ <p>Detecte automatiquement ton environnement et propose la configuration adaptee.</p>
51
51
  </div>
52
52
  </div>
53
53
  <div class="actions">
54
- <button class="btn btn-primary" onclick="app.startInstall()" aria-label="Start new installation">Install BYAN</button>
55
- <button class="btn btn-secondary" onclick="app.startUpdate()" aria-label="Update existing installation">Update Existing</button>
54
+ <button class="btn btn-primary" onclick="app.startInstall()" aria-label="Demarrer une nouvelle installation">Installer BYAN</button>
55
+ <button class="btn btn-secondary" onclick="app.startUpdate()" aria-label="Mettre a jour une installation existante">Mettre a jour</button>
56
56
  </div>
57
57
  </div>
58
58
  </section>
59
59
 
60
- <!-- Step 2: Detection -->
61
- <section class="step hidden" id="step-detection" role="region" aria-label="Environment detection">
60
+ <!-- Etape 2 : Detection -->
61
+ <section class="step hidden" id="step-detection" role="region" aria-label="Detection de l'environnement">
62
62
  <div class="step-content">
63
- <h2>Environment Detection</h2>
64
- <p class="lead">Scanning your system for installed platforms and tools.</p>
63
+ <h2>Detection de l'environnement</h2>
64
+ <p class="lead">Analyse de ta machine : plateformes et outils installes.</p>
65
65
  <div id="detection-results" class="detection-grid" aria-live="polite">
66
- <div class="spinner-container"><div class="spinner"></div><p>Detecting...</p></div>
66
+ <div class="spinner-container"><div class="spinner"></div><p>Detection en cours...</p></div>
67
67
  </div>
68
68
  <div class="actions">
69
- <button class="btn btn-secondary" onclick="app.goBack()">Back</button>
70
- <button class="btn btn-primary" onclick="app.showStep('mode')" id="btn-detection-next" disabled>Continue</button>
69
+ <button class="btn btn-secondary" onclick="app.goBack()">Retour</button>
70
+ <button class="btn btn-primary" onclick="app.showStep('mode')" id="btn-detection-next" disabled>Continuer</button>
71
71
  </div>
72
72
  </div>
73
73
  </section>
74
74
 
75
- <!-- Step 3: Mode Selection -->
76
- <section class="step hidden" id="step-mode" role="region" aria-label="Installation mode">
75
+ <!-- Etape 3 : Choix du mode -->
76
+ <section class="step hidden" id="step-mode" role="region" aria-label="Mode d'installation">
77
77
  <div class="step-content">
78
- <h2>Installation Mode</h2>
79
- <p class="lead">Choose how you want to install BYAN.</p>
78
+ <h2>Mode d'installation</h2>
79
+ <p class="lead">Choisis comment installer BYAN.</p>
80
80
  <div class="mode-cards">
81
- <button class="card" onclick="app.selectMode('auto')" aria-label="Auto mode: quick install with smart defaults">
82
- <div class="card-badge">Recommended</div>
81
+ <button class="card" onclick="app.selectMode('auto')" aria-label="Mode auto : installation rapide, tous les agents">
82
+ <div class="card-badge">Recommande</div>
83
83
  <h3>AUTO</h3>
84
- <p>Quick install with smart defaults based on detected environment.</p>
84
+ <p>Installation rapide : tous les agents, Claude + Codex detectes, defauts intelligents. On te demande juste ton prenom.</p>
85
85
  </button>
86
- <button class="card" onclick="app.selectMode('custom')" aria-label="Custom mode: guided interview">
87
- <h3>CUSTOM</h3>
88
- <p>Guided interview with recommendations for each option.</p>
86
+ <button class="card" onclick="app.selectMode('custom')" aria-label="Mode personnalise : entretien guide">
87
+ <h3>PERSONNALISE</h3>
88
+ <p>Entretien guide avec des recommandations pour chaque option.</p>
89
89
  </button>
90
- <button class="card" onclick="app.selectMode('manual')" aria-label="Manual mode: choose agents individually">
91
- <h3>MANUAL</h3>
92
- <p>Full control. Choose every agent and platform individually.</p>
90
+ <button class="card" onclick="app.selectMode('manual')" aria-label="Mode manuel : choisir chaque agent individuellement">
91
+ <h3>MANUEL</h3>
92
+ <p>Controle total. Choisis chaque agent et chaque plateforme.</p>
93
93
  </button>
94
94
  </div>
95
95
  <div class="actions">
96
- <button class="btn btn-secondary" onclick="app.goBack()">Back</button>
96
+ <button class="btn btn-secondary" onclick="app.goBack()">Retour</button>
97
97
  </div>
98
98
  </div>
99
99
  </section>
100
100
 
101
- <!-- Step 4: Configuration -->
101
+ <!-- Etape 4 : Configuration -->
102
102
  <section class="step hidden" id="step-config" role="region" aria-label="Configuration">
103
103
  <div class="step-content">
104
104
  <h2>Configuration</h2>
105
105
  <div id="config-form" class="config-form"></div>
106
106
  <div class="actions">
107
- <button class="btn btn-secondary" onclick="app.goBack()">Back</button>
108
- <button class="btn btn-primary" onclick="app.showPreview()">Preview</button>
107
+ <button class="btn btn-secondary" onclick="app.goBack()">Retour</button>
108
+ <button class="btn btn-primary" onclick="app.showPreview()">Recapitulatif</button>
109
109
  </div>
110
110
  </div>
111
111
  </section>
112
112
 
113
- <!-- Step 5: Preview -->
114
- <section class="step hidden" id="step-preview" role="region" aria-label="Installation preview">
113
+ <!-- Etape 5 : Recapitulatif -->
114
+ <section class="step hidden" id="step-preview" role="region" aria-label="Recapitulatif de l'installation">
115
115
  <div class="step-content">
116
- <h2>Installation Preview</h2>
117
- <p class="lead">Review your configuration before installing.</p>
116
+ <h2>Recapitulatif</h2>
117
+ <p class="lead">Verifie ta configuration avant d'installer.</p>
118
118
  <div id="preview-content" class="preview-block"></div>
119
119
  <div class="actions">
120
- <button class="btn btn-secondary" onclick="app.goBack()">Back</button>
121
- <button class="btn btn-primary" onclick="app.confirmInstall()">Confirm &amp; Install</button>
120
+ <button class="btn btn-secondary" onclick="app.goBack()">Retour</button>
121
+ <button class="btn btn-primary" onclick="app.confirmInstall()">Confirmer et installer</button>
122
122
  </div>
123
123
  </div>
124
124
  </section>
125
125
 
126
- <!-- Step 6: Progress -->
127
- <section class="step hidden" id="step-progress" role="region" aria-label="Installation progress">
126
+ <!-- Etape 6 : Progression -->
127
+ <section class="step hidden" id="step-progress" role="region" aria-label="Progression de l'installation">
128
128
  <div class="step-content">
129
- <h2 id="progress-title">Installing...</h2>
129
+ <h2 id="progress-title">Installation en cours...</h2>
130
130
  <div class="progress-container">
131
131
  <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
132
132
  <div class="progress-fill" id="progress-fill"></div>
133
133
  </div>
134
- <p class="progress-label" id="progress-label">Preparing...</p>
134
+ <p class="progress-label" id="progress-label">Preparation...</p>
135
135
  <p class="progress-pct" id="progress-pct">0%</p>
136
136
  </div>
137
137
  </div>
138
138
  </section>
139
139
 
140
- <!-- Step 7: Done -->
141
- <section class="step hidden" id="step-done" role="region" aria-label="Installation complete">
140
+ <!-- Etape 7 : Termine -->
141
+ <section class="step hidden" id="step-done" role="region" aria-label="Installation terminee">
142
142
  <div class="step-content">
143
143
  <div id="done-icon" class="done-icon" aria-hidden="true">&#10003;</div>
144
- <h2 id="done-title">Installation Complete</h2>
144
+ <h2 id="done-title">Installation terminee</h2>
145
145
  <div id="done-summary" class="done-summary"></div>
146
146
  <div class="actions">
147
- <button class="btn btn-primary" onclick="window.location.reload()">Start Over</button>
147
+ <button class="btn btn-primary" onclick="window.location.reload()">Recommencer</button>
148
148
  </div>
149
149
  </div>
150
150
  </section>
151
151
 
152
- <!-- Update: Check -->
153
- <section class="step hidden" id="step-update-check" role="region" aria-label="Update check">
152
+ <!-- Mise a jour : verification -->
153
+ <section class="step hidden" id="step-update-check" role="region" aria-label="Verification des mises a jour">
154
154
  <div class="step-content">
155
- <h2>Checking for Updates</h2>
155
+ <h2>Verification des mises a jour</h2>
156
156
  <div id="update-info" aria-live="polite">
157
- <div class="spinner-container"><div class="spinner"></div><p>Checking...</p></div>
157
+ <div class="spinner-container"><div class="spinner"></div><p>Verification...</p></div>
158
158
  </div>
159
159
  <div class="actions" id="update-check-actions" style="display:none">
160
- <button class="btn btn-secondary" onclick="app.showStep('welcome')">Back</button>
161
- <button class="btn btn-primary" onclick="app.confirmUpdate()" id="btn-update-confirm" disabled>Update Now</button>
160
+ <button class="btn btn-secondary" onclick="app.showStep('welcome')">Retour</button>
161
+ <button class="btn btn-primary" onclick="app.confirmUpdate()" id="btn-update-confirm" disabled>Mettre a jour</button>
162
162
  </div>
163
163
  </div>
164
164
  </section>
165
165
 
166
- <!-- Update: Diff -->
167
- <section class="step hidden" id="step-update-diff" role="region" aria-label="Changes preview">
166
+ <!-- Mise a jour : apercu des changements -->
167
+ <section class="step hidden" id="step-update-diff" role="region" aria-label="Apercu des changements">
168
168
  <div class="step-content">
169
- <h2>Changes Preview</h2>
169
+ <h2>Apercu des changements</h2>
170
170
  <div id="update-diff" class="code-block"></div>
171
171
  <div class="actions">
172
- <button class="btn btn-secondary" onclick="app.showStep('update-check')">Cancel</button>
173
- <button class="btn btn-primary" onclick="app.confirmUpdate()">Update Now</button>
172
+ <button class="btn btn-secondary" onclick="app.showStep('update-check')">Annuler</button>
173
+ <button class="btn btn-primary" onclick="app.confirmUpdate()">Mettre a jour</button>
174
174
  </div>
175
175
  </div>
176
176
  </section>
@@ -179,7 +179,7 @@
179
179
  <footer>
180
180
  <div id="log-panel" class="log-panel">
181
181
  <button class="log-header" onclick="app.toggleLogs()" aria-expanded="false" aria-controls="log-content">
182
- <span>Logs</span>
182
+ <span>Journal</span>
183
183
  <span class="log-badge hidden" id="log-badge">0</span>
184
184
  <span class="log-chevron" id="log-chevron" aria-hidden="true">&#9650;</span>
185
185
  </button>
@@ -25,7 +25,10 @@ const MIME_TYPES = {
25
25
 
26
26
  class ByanWebUI {
27
27
  constructor(options = {}) {
28
- this.port = options.port || 3000;
28
+ // ?? and not || : port 0 is a VALID value (the OS assigns a free port and
29
+ // the fork parent reads it back from the ready message). `0 || 3000` would
30
+ // silently force 3000 and crash on EADDRINUSE when 3000 is busy.
31
+ this.port = options.port ?? 3000;
29
32
  this.projectRoot = options.projectRoot || process.cwd();
30
33
  this.publicDir = path.join(__dirname, 'public');
31
34
  this.server = null;
@@ -330,8 +333,13 @@ class ByanWebUI {
330
333
  }
331
334
 
332
335
  if (require.main === module) {
333
- const port = parseInt(process.argv[2], 10) || 3000;
334
- const projectRoot = process.argv[3] || path.resolve(__dirname, '..', '..', '..');
336
+ // Port order: argv[2] (explicit CLI), then env PORT (the Electron fork
337
+ // passes PORT=0 for an OS-assigned port), then 3000. Number.isFinite and
338
+ // not || : 0 is a valid requested port here.
339
+ const argPort = parseInt(process.argv[2], 10);
340
+ const envPort = parseInt(process.env.PORT ?? '', 10);
341
+ const port = Number.isFinite(argPort) ? argPort : (Number.isFinite(envPort) ? envPort : 3000);
342
+ const projectRoot = process.argv[3] || process.env.BYAN_PROJECT_ROOT || path.resolve(__dirname, '..', '..', '..');
335
343
  const ui = new ByanWebUI({ port, projectRoot });
336
344
  ui.start().then(() => {
337
345
  console.log(`Project root: ${ui.projectRoot}`);
@@ -93,7 +93,10 @@ export const DEEP_PREFIX = 'deep-';
93
93
  const VERIFICATION_KEYWORDS = ['verify', 'validate', 'check', 'assert', 'gate', 'lint', 'audit', 'review'];
94
94
  const ANALYSIS_KEYWORDS = ['analy', 'design', 'architect', 'assess', 'evaluate', 'strategy', 'risk', 'nfr', 'recommend', 'judge', 'score', 'coverage', 'synthes'];
95
95
  const IMPLEMENTATION_KEYWORDS = ['implement', 'build', 'write', 'generate', 'create', 'dev', 'rgr', 'refactor', 'fix', 'scaffold', 'save', 'optimize', 'aggregate', 'report', 'present', 'plan', 'map', 'select', 'subprocess', 'sub-'];
96
- const EXPLORATION_KEYWORDS = ['load', 'read', 'scan', 'list', 'parse', 'detect', 'discover', 'fetch', 'lookup', 'source-tree', 'mode-detection'];
96
+ // cartograph/inventaire/recensement... : vocabulaire de cartographie de
97
+ // l'existant (lecture + synthese), francais inclus — cas terrain byan_web ou
98
+ // des feuilles de scan DISCOVERY non reconnues heritaient d'une session Fable 5.
99
+ const EXPLORATION_KEYWORDS = ['load', 'read', 'scan', 'list', 'parse', 'detect', 'discover', 'fetch', 'lookup', 'source-tree', 'mode-detection', 'cartograph', 'inventaire', 'inventory', 'recensement', 'census', 'enumerate', 'survey', 'crawl'];
97
100
 
98
101
  function matchesAny(text, keywords) {
99
102
  return keywords.some((kw) => text.includes(kw));
@@ -115,6 +118,10 @@ export function classifyLeaf(leaf) {
115
118
  // (the analysis escape hatch, classified as the deep IMPLEMENTATION bucket).
116
119
  if (label.startsWith(MECHANICAL_PREFIX)) return LEAF_TYPES.MECHANICAL;
117
120
  if (label.startsWith(DEEP_PREFIX)) return LEAF_TYPES.IMPLEMENTATION;
121
+ // 'map:' (deux-points) = convention de cartographie de l'existant (scan) ->
122
+ // exploration, AVANT le mot-cle 'map' d'implementation qui sinon l'avale.
123
+ // 'map-' (tiret, ex. map-criteria) reste une transformation profonde.
124
+ if (label.startsWith('map:')) return LEAF_TYPES.EXPLORATION;
118
125
  if (matchesAny(label, VERIFICATION_KEYWORDS)) return LEAF_TYPES.VERIFICATION;
119
126
  if (matchesAny(label, ANALYSIS_KEYWORDS)) return LEAF_TYPES.ANALYSIS;
120
127
  if (matchesAny(label, IMPLEMENTATION_KEYWORDS)) return LEAF_TYPES.IMPLEMENTATION;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-byan-agent",
3
- "version": "2.58.1",
3
+ "version": "2.59.1",
4
4
  "description": "BYAN v2.8 - Intelligent AI agent creator with ELO trust system + scientific fact-check + Hermes universal dispatcher + native Claude Code integration (hooks, skills, MCP server). Multi-platform (Claude Code, Codex). Merise Agile + TDD + 71 Mantras. ~54% LLM cost savings.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -87,7 +87,8 @@
87
87
  "js-yaml": "^4.1.0",
88
88
  "ora": "^5.4.1",
89
89
  "uuid": "^13.0.0",
90
- "winston": "^3.19.0"
90
+ "winston": "^3.19.0",
91
+ "ws": "^8.20.0"
91
92
  },
92
93
  "bundleDependencies": [
93
94
  "byan-platform-config"