oft-agt 0.5.16 → 0.5.17

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/cli.mjs CHANGED
@@ -51,6 +51,7 @@ async function credentials(config) {
51
51
  }
52
52
  async function stopBot() {
53
53
  const current = child;
54
+ child = null;
54
55
  if (!current || current.exitCode !== null || current.signalCode) return;
55
56
  await new Promise(resolve => { const timer = setTimeout(() => current.kill('SIGKILL'), 5000); current.once('exit', () => { clearTimeout(timer); resolve(); }); current.kill('SIGTERM'); });
56
57
  }
@@ -89,6 +90,7 @@ async function deploy(config, message, notify) {
89
90
  await run(process.execPath, ['bot.mjs', '--deploy'], { cwd: target, env, stdio: 'ignore' });
90
91
  const previous = child;
91
92
  const previousId = active;
93
+ child = null;
92
94
  if (previous && previous.exitCode === null && !previous.signalCode) {
93
95
  await new Promise(resolve => { const timeout = setTimeout(() => { previous.kill('SIGKILL'); }, 5000); previous.once('exit', () => { clearTimeout(timeout); resolve(); }); previous.kill('SIGTERM'); });
94
96
  }
@@ -109,7 +111,8 @@ async function deploy(config, message, notify) {
109
111
  }
110
112
  throw error;
111
113
  }
112
- child.once('exit', () => { if (active === message.id) notify('failed'); });
114
+ const deployedChild=child;
115
+ deployedChild.once('exit', () => { if (child === deployedChild && active === message.id) notify('runtime-failed'); });
113
116
  active = message.id;
114
117
  await save(path.join(home, 'active.json'), { id: message.id });
115
118
  notify('running');
@@ -203,7 +206,7 @@ async function start(config) {
203
206
  if (message.type === 'deploy') {
204
207
  console.log(`[${new Date().toISOString()}] Nouveau déploiement reçu.`);
205
208
  if (await exists(path.join(home, 'paused.json'))) await unlink(path.join(home, 'paused.json'));
206
- try { await deploy(config, message, async state => { send({ type: 'deployment-status', id: message.id, state, runtimeVersion:state==='running'?await runtimeVersion():null }); console.log(({ received: 'Déploiement validé.', installing: 'Préparation du bot.', running: 'Déploiement terminé. Bot démarré.', failed: 'Échec du déploiement.' })[state] || 'État du déploiement modifié.'); }); }
209
+ try { await deploy(config, message, async state => { if(state==='runtime-failed'){send({type:'runtime-status',state:'failed'});return;} send({ type: 'deployment-status', id: message.id, state, runtimeVersion:state==='running'?await runtimeVersion():null }); console.log(({ received: 'Déploiement validé.', installing: 'Préparation du bot.', running: 'Déploiement terminé. Bot démarré.', failed: 'Échec du déploiement.' })[state] || 'État du déploiement modifié.'); }); }
207
210
  catch { send({ type: 'deployment-status', id: message.id, state: 'failed' }); console.error('Déploiement refusé ou échoué.'); }
208
211
  }
209
212
  }).catch(() => console.error('Message refusé.'));
@@ -233,7 +236,7 @@ function printHelp() {
233
236
  status Afficher l’état local
234
237
  logs Lire les 100 dernières lignes du journal
235
238
  token [--stdin] Régénérer l’authentification agent ; --stdin lit 64 caractères hexadécimaux
236
- remove --yes Révoquer la liaison et supprimer les données locales de cette instance
239
+ remove | delete --yes Supprimer une instance arrêtée de la liste et révoquer sa liaison
237
240
  list Afficher les instances installées
238
241
  help Afficher cette aide
239
242
  Options : --bot=IDENTIFIANT_COURT (voir list) pour choisir un bot ; start --foreground pour diagnostiquer.
@@ -242,7 +245,7 @@ Documentation : https://doc-builder.oftone.fr/agent`);
242
245
  }
243
246
  async function main() {
244
247
  const [requestedCommand, ...args] = process.argv.slice(2);
245
- const command = requestedCommand || 'login';
248
+ const command = requestedCommand==='delete'?'remove':requestedCommand || 'login';
246
249
  const source = path.dirname(fileURLToPath(import.meta.url));
247
250
  if (['help', '--help', '-h'].includes(command)) { printHelp(); return; }
248
251
  if (command === 'list') { for (const instance of await listInstances(baseHome)) console.log(`${instance.agentId.slice(0, 8)} · ${(await localStatus(instance.home)).running ? 'actif' : 'arrêté'}`); return; }
@@ -327,7 +330,8 @@ async function main() {
327
330
  }
328
331
  if (command === 'remove') {
329
332
  if (!args.includes('--yes')) { console.log('Supprime l’agent sélectionné et ses données locales, y compris son token Discord. Relancez avec remove --yes pour confirmer.'); return; }
330
- await stopBackground(home); const config = JSON.parse(await readFile(configPath, 'utf8'));
333
+ const state=await localStatus(home);if(state.running||state.starting||state.legacy)throw Error('REMOVE_RUNNING');
334
+ const config = JSON.parse(await readFile(configPath, 'utf8'));
331
335
  let revoked = false;
332
336
  try { const response = await fetch(`${config.relay}/v1/agents/${config.object}/remove`, { method: 'POST', headers: { Authorization: `Bearer ${config.credential}` }, signal: AbortSignal.timeout(15000) }); revoked = response.ok; } catch {}
333
337
  await removeLocalInstance(home, baseHome, config);
@@ -335,5 +339,5 @@ async function main() {
335
339
  }
336
340
  throw new Error('COMMAND_UNKNOWN');
337
341
  }
338
- main().catch(error => { const messages = { LOGIN_BUSY: 'Une connexion Discord est déjà en cours sur cette machine.', LOGIN_EXPIRED: 'La demande a expiré. Relancez npx oft-agt login.', LOGIN_START_FAILED: 'Impossible de démarrer la connexion. Réessayez dans quelques minutes.', LOGIN_FAILED: 'Connexion refusée. Relancez npx oft-agt login.', AUTH_ROTATION_BUSY: 'Une modification de l’authentification est déjà en cours pour cette instance. Réessayez après sa fin.', COMMAND_UNKNOWN: 'Commande inconnue. Consultez oftone-agent help.', LEGACY_FOREGROUND: 'Un ancien agent fonctionne au premier plan. Arrêtez-le avec Ctrl+C une seule fois, puis utilisez start.', DAEMON_START_FAILED: 'L’agent n’a pas démarré. Consultez logs.', DAEMON_START_TIMEOUT: 'Démarrage non confirmé. Consultez status et logs avant de réessayer.', DAEMON_STOP_TIMEOUT: 'L’arrêt n’est pas encore confirmé. Consultez status et logs.', AUTH_ROTATION_FAILED: 'Changement d’authentification non confirmé. Réessayez token ou start pour reprendre sans perdre la liaison.', AUTH_ROTATION_INVALID: 'Token d’authentification invalide : 64 caractères hexadécimaux attendus.', PAIRING_INVALID: 'Commande de liaison invalide. Copiez à nouveau la commande complète depuis le dashboard.', PAIRING_REJECTED: 'Commande de liaison expirée, déjà utilisée ou révoquée. Générez-en une nouvelle depuis le bot concerné.', INSTANCE_INVALID: 'Identifiant d’instance invalide. Copiez la commande depuis les paramètres du bot concerné.', INSTANCE_NOT_FOUND: 'Cette liaison n’est pas installée sur cette machine. Utilisez la commande locale de cette instance ou configurez une nouvelle liaison.', INSTANCE_REQUIRED: 'Précisez l’instance avec la commande affichée dans les paramètres du bot ou la commande locale affichée à l’installation.', INSTANCE_EXISTS: 'Cette instance existe déjà. Utilisez sa commande locale de démarrage.', AGENT_ACTIVE: 'Cet agent est déjà actif. Arrêtez uniquement le processus de cette instance avant de le relancer.' }; console.error(messages[error.code || error.message] || 'Échec de l’agent. Vérifiez la liaison et la configuration locale. Aucun secret affiché.'); process.exitCode = 1; });
342
+ main().catch(error => { const messages = { REMOVE_RUNNING:'Arrêtez ce bot avec stop avant de le supprimer de la liste.', LOGIN_BUSY: 'Une connexion Discord est déjà en cours sur cette machine.', LOGIN_EXPIRED: 'La demande a expiré. Relancez npx oft-agt login.', LOGIN_START_FAILED: 'Impossible de démarrer la connexion. Réessayez dans quelques minutes.', LOGIN_FAILED: 'Connexion refusée. Relancez npx oft-agt login.', AUTH_ROTATION_BUSY: 'Une modification de l’authentification est déjà en cours pour cette instance. Réessayez après sa fin.', COMMAND_UNKNOWN: 'Commande inconnue. Consultez oftone-agent help.', LEGACY_FOREGROUND: 'Un ancien agent fonctionne au premier plan. Arrêtez-le avec Ctrl+C une seule fois, puis utilisez start.', DAEMON_START_FAILED: 'L’agent n’a pas démarré. Consultez logs.', DAEMON_START_TIMEOUT: 'Démarrage non confirmé. Consultez status et logs avant de réessayer.', DAEMON_STOP_TIMEOUT: 'L’arrêt n’est pas encore confirmé. Consultez status et logs.', AUTH_ROTATION_FAILED: 'Changement d’authentification non confirmé. Réessayez token ou start pour reprendre sans perdre la liaison.', AUTH_ROTATION_INVALID: 'Token d’authentification invalide : 64 caractères hexadécimaux attendus.', PAIRING_INVALID: 'Commande de liaison invalide. Copiez à nouveau la commande complète depuis le dashboard.', PAIRING_REJECTED: 'Commande de liaison expirée, déjà utilisée ou révoquée. Générez-en une nouvelle depuis le bot concerné.', INSTANCE_INVALID: 'Identifiant d’instance invalide. Copiez la commande depuis les paramètres du bot concerné.', INSTANCE_NOT_FOUND: 'Cette liaison n’est pas installée sur cette machine. Utilisez la commande locale de cette instance ou configurez une nouvelle liaison.', INSTANCE_REQUIRED: 'Précisez l’instance avec la commande affichée dans les paramètres du bot ou la commande locale affichée à l’installation.', INSTANCE_EXISTS: 'Cette instance existe déjà. Utilisez sa commande locale de démarrage.', AGENT_ACTIVE: 'Cet agent est déjà actif. Arrêtez uniquement le processus de cette instance avant de le relancer.' }; console.error(messages[error.code || error.message] || 'Échec de l’agent. Vérifiez la liaison et la configuration locale. Aucun secret affiché.'); process.exitCode = 1; });
339
343
 
package/compile-plan.mjs CHANGED
@@ -46,9 +46,9 @@ export function compile(input) {
46
46
  if (!plain(command)) fail(`Commande ${commandIndex + 1} : configuration absente.`);
47
47
 
48
48
  validateEventGraph(command);
49
- const name = text(command.name ?? entry.name, 'Nom de commande', 32, true);
49
+ const name = text(command.name ?? entry.name, 'Nom', command.trigger?.kind==='event'?100:32, true);
50
50
 
51
- if (!/^[a-z0-9_-]{1,32}$/.test(name)) fail(`/${name} : utilisez des minuscules, chiffres, tirets ou underscores.`);
51
+ if (command.trigger?.kind!=='event' && !/^[a-z0-9_-]{1,32}$/.test(name)) fail(`/${name} : utilisez des minuscules, chiffres, tirets ou underscores.`);
52
52
 
53
53
  if (names.has(name)) fail(`Commande dupliquée : /${name}.`);
54
54
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "oft-agt",
3
- "version": "0.5.16",
3
+ "version": "0.5.17",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "oft-agt",
9
- "version": "0.5.16",
9
+ "version": "0.5.17",
10
10
  "license": "UNLICENSED",
11
11
  "dependencies": {
12
12
  "discord.js": "^14.14.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oft-agt",
3
- "version": "0.5.16",
3
+ "version": "0.5.17",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -1 +1 @@
1
- export const RUNTIME_VERSION = '0.5.16';
1
+ export const RUNTIME_VERSION = '0.5.17';
package/usage.mjs CHANGED
@@ -12,7 +12,7 @@ export async function createUsageCollector(home, now = () => Date.now()) {
12
12
  let writing = Promise.resolve();
13
13
  return {
14
14
  record(event) {
15
- if (event?.type !== 'usage' || !/^[a-z0-9_-]{1,32}$/.test(event.command || '') || typeof event.success !== 'boolean' || !Number.isFinite(event.durationMs) || event.durationMs < 0 || event.durationMs > 900000) return;
15
+ if (event?.type !== 'usage' || (typeof event.command!=='string'||!event.command.trim()||event.command.length>100||/[\u0000-\u001f\u007f]/.test(event.command)) || typeof event.success !== 'boolean' || !Number.isFinite(event.durationMs) || event.durationMs < 0 || event.durationMs > 900000) return;
16
16
  const current = Math.floor(now() / HOUR) * HOUR;
17
17
  const hour = event.hour ?? current;
18
18
  if (!Number.isSafeInteger(hour) || hour % HOUR || hour > current || hour < current - 719 * HOUR) return;
package/version.mjs CHANGED
@@ -1 +1 @@
1
- export const AGENT_VERSION = '0.5.16';
1
+ export const AGENT_VERSION = '0.5.17';