fluxy-bot 0.5.36 → 0.5.39

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/bin/cli.js CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawn, execSync, spawnSync } from 'child_process';
4
- import readline from 'readline';
5
4
  import fs from 'fs';
6
5
  import path from 'path';
7
6
  import os from 'os';
@@ -70,8 +69,9 @@ ExecStart=${nodePath} --import tsx/esm ${dataDir}/supervisor/index.ts
70
69
  Restart=on-failure
71
70
  RestartSec=5
72
71
  Environment=HOME=${home}
73
- Environment=NODE_ENV=production
74
- Environment=PATH=${nodeBinDir}:/usr/local/bin:/usr/bin:/bin
72
+ Environment=NODE_ENV=development
73
+ Environment=NODE_PATH=${dataDir}/node_modules
74
+ Environment=PATH=${nodeBinDir}:${dataDir}/node_modules/.bin:/usr/local/bin:/usr/bin:/bin
75
75
  StandardOutput=journal
76
76
  StandardError=journal
77
77
  SyslogIdentifier=fluxy
@@ -81,16 +81,6 @@ WantedBy=multi-user.target
81
81
  `;
82
82
  }
83
83
 
84
- function askQuestion(query) {
85
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
86
- return new Promise((resolve) => {
87
- rl.question(query, (answer) => {
88
- rl.close();
89
- resolve(answer);
90
- });
91
- });
92
- }
93
-
94
84
  // ── UI helpers ──
95
85
 
96
86
  const c = {
@@ -215,16 +205,28 @@ function finalMessage(tunnelUrl, relayUrl) {
215
205
  ${c.pink}${c.bold}${link(relayUrl)}${c.reset}`);
216
206
  }
217
207
 
218
- console.log(`
208
+ if (os.platform() === 'linux') {
209
+ console.log(`
210
+ ${c.dim}─────────────────────────────────${c.reset}
211
+
212
+ ${c.bold}${c.white}Commands:${c.reset}
213
+ ${c.dim}Status${c.reset} ${c.pink}fluxy daemon status${c.reset}
214
+ ${c.dim}Logs${c.reset} ${c.pink}fluxy daemon logs${c.reset}
215
+ ${c.dim}Restart${c.reset} ${c.pink}fluxy daemon restart${c.reset}
216
+ ${c.dim}Stop${c.reset} ${c.pink}fluxy daemon stop${c.reset}
217
+ ${c.dim}Update${c.reset} ${c.pink}fluxy update${c.reset}
218
+ `);
219
+ } else {
220
+ console.log(`
219
221
  ${c.dim}─────────────────────────────────${c.reset}
220
222
 
221
223
  ${c.bold}${c.white}Commands:${c.reset}
222
224
  ${c.dim}Status${c.reset} ${c.pink}fluxy status${c.reset}
223
- ${c.dim}Update${c.reset} ${c.pink}fluxy update${c.reset}${os.platform() === 'linux' ? `
224
- ${c.dim}Daemon${c.reset} ${c.pink}fluxy daemon${c.reset}` : ''}
225
+ ${c.dim}Update${c.reset} ${c.pink}fluxy update${c.reset}
225
226
 
226
- ${c.dim}Press Ctrl+C to stop the bot${c.reset}
227
+ ${c.dim}Press Ctrl+C to stop${c.reset}
227
228
  `);
229
+ }
228
230
  }
229
231
 
230
232
  // ── Steps ──
@@ -387,6 +389,9 @@ async function init() {
387
389
 
388
390
  createConfig();
389
391
 
392
+ const isLinux = os.platform() === 'linux';
393
+ const hasSystemd = isLinux && (() => { try { execSync('systemctl --version', { stdio: 'ignore' }); return true; } catch { return false; } })();
394
+
390
395
  const steps = [
391
396
  'Creating config',
392
397
  'Installing cloudflared',
@@ -394,6 +399,7 @@ async function init() {
394
399
  'Connecting tunnel',
395
400
  'Verifying connection',
396
401
  'Preparing dashboard',
402
+ ...(hasSystemd ? ['Setting up auto-start daemon'] : []),
397
403
  ];
398
404
 
399
405
  const stepper = new Stepper(steps);
@@ -425,28 +431,32 @@ async function init() {
425
431
  await Promise.race([viteWarm, new Promise(r => setTimeout(r, 30_000))]);
426
432
  stepper.advance();
427
433
 
434
+ // Install systemd daemon on Linux
435
+ if (hasSystemd) {
436
+ child.removeAllListeners('exit');
437
+ child.kill('SIGTERM');
438
+ await new Promise((r) => setTimeout(r, 4000));
439
+ const nodePath = process.execPath;
440
+ const realHome = os.homedir();
441
+ const res = spawnSync(process.execPath, [process.argv[1], 'daemon', 'install'], {
442
+ stdio: 'pipe',
443
+ env: { ...process.env, FLUXY_NODE_PATH: nodePath, FLUXY_REAL_HOME: realHome },
444
+ });
445
+ stepper.advance();
446
+ stepper.finish();
447
+ finalMessage(tunnelUrl, relayUrl);
448
+ if (res.status === 0) {
449
+ console.log(` ${c.blue}✔${c.reset} Daemon installed — Fluxy will auto-start on boot.`);
450
+ } else {
451
+ console.log(` ${c.yellow}⚠${c.reset} Daemon install failed. Run ${c.pink}fluxy daemon install${c.reset} manually.`);
452
+ }
453
+ console.log('');
454
+ process.exit(res.status ?? 0);
455
+ }
456
+
428
457
  stepper.finish();
429
458
  finalMessage(tunnelUrl, relayUrl);
430
459
 
431
- // Offer daemon install on Linux
432
- if (os.platform() === 'linux' && process.stdin.isTTY) {
433
- try {
434
- const answer = await askQuestion(` ${c.bold}Install as a system daemon (auto-start on boot)?${c.reset} ${c.dim}[Y/n]${c.reset} `);
435
- if (!answer || answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
436
- console.log(`\n ${c.dim}Stopping foreground server...${c.reset}`);
437
- child.kill('SIGTERM');
438
- await new Promise((r) => setTimeout(r, 2000));
439
- const nodePath = process.execPath;
440
- const realHome = os.homedir();
441
- const result = spawnSync(process.execPath, [process.argv[1], 'daemon', 'install'], {
442
- stdio: 'inherit',
443
- env: { ...process.env, FLUXY_NODE_PATH: nodePath, FLUXY_REAL_HOME: realHome },
444
- });
445
- process.exit(result.status ?? 0);
446
- }
447
- } catch {}
448
- }
449
-
450
460
  child.stdout.on('data', (d) => {
451
461
  process.stdout.write(` ${c.dim}${d.toString().trim()}${c.reset}\n`);
452
462
  });
@@ -462,9 +472,20 @@ async function start() {
462
472
  return init();
463
473
  }
464
474
 
475
+ const isLinux = os.platform() === 'linux';
476
+ const hasSystemd = isLinux && (() => { try { execSync('systemctl --version', { stdio: 'ignore' }); return true; } catch { return false; } })();
477
+ const needsDaemon = hasSystemd && !isServiceInstalled();
478
+
465
479
  banner();
466
480
 
467
- const steps = ['Loading config', 'Starting server', 'Connecting tunnel', 'Verifying connection', 'Preparing dashboard'];
481
+ const steps = [
482
+ 'Loading config',
483
+ 'Starting server',
484
+ 'Connecting tunnel',
485
+ 'Verifying connection',
486
+ 'Preparing dashboard',
487
+ ...(needsDaemon ? ['Setting up auto-start daemon'] : []),
488
+ ];
468
489
  const stepper = new Stepper(steps);
469
490
  stepper.start();
470
491
 
@@ -488,28 +509,32 @@ async function start() {
488
509
  await Promise.race([viteWarm, new Promise(r => setTimeout(r, 30_000))]);
489
510
  stepper.advance();
490
511
 
512
+ // Install systemd daemon on Linux if not already installed
513
+ if (needsDaemon) {
514
+ child.removeAllListeners('exit');
515
+ child.kill('SIGTERM');
516
+ await new Promise((r) => setTimeout(r, 4000));
517
+ const nodePath = process.execPath;
518
+ const realHome = os.homedir();
519
+ const res = spawnSync(process.execPath, [process.argv[1], 'daemon', 'install'], {
520
+ stdio: 'pipe',
521
+ env: { ...process.env, FLUXY_NODE_PATH: nodePath, FLUXY_REAL_HOME: realHome },
522
+ });
523
+ stepper.advance();
524
+ stepper.finish();
525
+ finalMessage(tunnelUrl, relayUrl);
526
+ if (res.status === 0) {
527
+ console.log(` ${c.blue}✔${c.reset} Daemon installed — Fluxy will auto-start on boot.`);
528
+ } else {
529
+ console.log(` ${c.yellow}⚠${c.reset} Daemon install failed. Run ${c.pink}fluxy daemon install${c.reset} manually.`);
530
+ }
531
+ console.log('');
532
+ process.exit(res.status ?? 0);
533
+ }
534
+
491
535
  stepper.finish();
492
536
  finalMessage(tunnelUrl, relayUrl);
493
537
 
494
- // Offer daemon install on Linux if not already installed
495
- if (os.platform() === 'linux' && !isServiceInstalled() && process.stdin.isTTY) {
496
- try {
497
- const answer = await askQuestion(` ${c.bold}Install as a system daemon (auto-start on boot)?${c.reset} ${c.dim}[Y/n]${c.reset} `);
498
- if (!answer || answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
499
- console.log(`\n ${c.dim}Stopping foreground server...${c.reset}`);
500
- child.kill('SIGTERM');
501
- await new Promise((r) => setTimeout(r, 2000));
502
- const nodePath = process.execPath;
503
- const realHome = os.homedir();
504
- const result = spawnSync(process.execPath, [process.argv[1], 'daemon', 'install'], {
505
- stdio: 'inherit',
506
- env: { ...process.env, FLUXY_NODE_PATH: nodePath, FLUXY_REAL_HOME: realHome },
507
- });
508
- process.exit(result.status ?? 0);
509
- }
510
- } catch {}
511
- }
512
-
513
538
  child.stdout.on('data', (d) => {
514
539
  process.stdout.write(` ${c.dim}${d.toString().trim()}${c.reset}\n`);
515
540
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.5.36",
3
+ "version": "0.5.39",
4
4
  "description": "Self-hosted, self-evolving AI agent with its own dashboard.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,6 +37,16 @@ app.use((_req, res) => {
37
37
  res.status(404).json({ error: 'Not found' });
38
38
  });
39
39
 
40
- app.listen(PORT, () => {
40
+ const server = app.listen(PORT, () => {
41
41
  console.log(`[backend] Listening on port ${PORT}`);
42
42
  });
43
+
44
+ server.on('error', (err: NodeJS.ErrnoException) => {
45
+ console.error(`[backend] Server error: ${err.message}`);
46
+ process.exit(1);
47
+ });
48
+
49
+ // Keep process alive — prevent exit on unhandled rejection
50
+ process.on('unhandledRejection', (err) => {
51
+ console.error('[backend] Unhandled rejection:', err);
52
+ });