fluxy-bot 0.4.18 → 0.4.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.4.18",
3
+ "version": "0.4.20",
4
4
  "description": "Self-hosted, self-evolving AI agent with its own dashboard.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -14,7 +14,7 @@ import { spawnBackend, stopBackend, getBackendPort, isBackendAlive, resetBackend
14
14
  import { updateTunnelUrl, startHeartbeat, stopHeartbeat, disconnect } from '../shared/relay.js';
15
15
  import { startFluxyAgentQuery, stopFluxyAgentQuery, clearFluxySession } from './fluxy-agent.js';
16
16
  import { ensureFileDirs, saveAttachment, type SavedFile } from './file-saver.js';
17
- import { startViteDevServers, stopViteDevServers, reloadDashboard } from './vite-dev.js';
17
+ import { startViteDevServers, stopViteDevServers } from './vite-dev.js';
18
18
  import { execSync } from 'child_process';
19
19
 
20
20
  const DIST_FLUXY = path.join(PKG_DIR, 'dist-fluxy');
@@ -57,10 +57,15 @@ export async function startSupervisor() {
57
57
  const workerPort = getWorkerPort(config.port);
58
58
  const backendPort = getBackendPort(config.port);
59
59
 
60
- // Start Vite dev server for dashboard HMR
60
+ // Create HTTP server first (Vite needs it for HMR WebSocket)
61
+ // The request handler is set up later via server.on('request')
62
+ const server = http.createServer();
63
+
64
+ // Start Vite dev server — pass supervisor server so Vite attaches HMR WebSocket directly
61
65
  console.log('[supervisor] Starting Vite dev server...');
62
- const vitePorts = await startViteDevServers(config.port);
66
+ const vitePorts = await startViteDevServers(config.port, server);
63
67
  console.log(`[supervisor] Vite ready — dashboard :${vitePorts.dashboard}`);
68
+ console.log(`[supervisor] Upgrade listeners on server: ${server.listenerCount('upgrade')}`);
64
69
 
65
70
  // Ensure file storage dirs exist
66
71
  ensureFileDirs();
@@ -152,8 +157,8 @@ export async function startSupervisor() {
152
157
  });
153
158
  }
154
159
 
155
- // HTTP server — proxies to Vite dev servers + worker API
156
- const server = http.createServer(async (req, res) => {
160
+ // HTTP request handler — proxies to Vite dev servers + worker API
161
+ server.on('request', async (req, res) => {
157
162
  // Fluxy widget — served directly (not part of Vite build)
158
163
  if (req.url === '/fluxy/widget.js') {
159
164
  console.log('[supervisor] Serving /fluxy/widget.js directly');
@@ -421,11 +426,10 @@ export async function startSupervisor() {
421
426
  // Intercept bot:done — Vite HMR handles file changes automatically
422
427
  if (type === 'bot:done') {
423
428
  if (eventData.usedFileTools) {
424
- console.log('[supervisor] File tools used — reloading dashboard + restarting backend');
429
+ console.log('[supervisor] File tools used — Vite HMR handles frontend, restarting backend');
425
430
  resetBackendRestarts();
426
431
  stopBackend();
427
432
  spawnBackend(backendPort);
428
- reloadDashboard();
429
433
  }
430
434
  return; // don't forward bot:done to client
431
435
  }
@@ -508,41 +512,30 @@ export async function startSupervisor() {
508
512
  });
509
513
  });
510
514
 
515
+ // Fluxy chat WebSocket — Vite HMR is handled automatically (hmr.server = this server)
511
516
  server.on('upgrade', async (req, socket: net.Socket, head) => {
512
- console.log(`[supervisor] WebSocket upgrade: ${req.url}`);
513
-
514
- if (req.url?.startsWith('/fluxy/ws')) {
515
- // Auth check for WebSocket
516
- const needsAuth = await isAuthRequired();
517
- if (needsAuth) {
518
- const urlObj = new URL(req.url, `http://${req.headers.host}`);
519
- const token = urlObj.searchParams.get('token');
520
- if (!token || !(await validateToken(token))) {
521
- console.log('[supervisor] WS auth failed — rejecting');
522
- socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
523
- socket.destroy();
524
- return;
525
- }
526
- }
517
+ console.log(`[supervisor] WebSocket upgrade: ${req.url} | protocol=${req.headers['sec-websocket-protocol'] || 'none'}`);
527
518
 
528
- console.log('[supervisor] → Fluxy chat WebSocket');
529
- fluxyWss.handleUpgrade(req, socket, head, (ws) => fluxyWss.emit('connection', ws, req));
519
+ if (!req.url?.startsWith('/fluxy/ws')) {
520
+ console.log('[supervisor] Letting Vite handle this upgrade');
530
521
  return;
531
522
  }
532
523
 
533
- // Route HMR WebSocket to dashboard Vite dev server
534
- const targetPort = vitePorts.dashboard;
535
- console.log(`[supervisor] → Vite HMR (dashboard) :${targetPort}`);
536
-
537
- const proxy = net.connect(targetPort, () => {
538
- const headers = Object.entries(req.headers).map(([k, v]) => `${k}: ${v}`).join('\r\n');
539
- proxy.write(`GET ${req.url} HTTP/1.1\r\n${headers}\r\n\r\n`);
540
- if (head.length > 0) proxy.write(head);
541
- socket.pipe(proxy).pipe(socket);
542
- });
524
+ // Auth check for WebSocket
525
+ const needsAuth = await isAuthRequired();
526
+ if (needsAuth) {
527
+ const urlObj = new URL(req.url, `http://${req.headers.host}`);
528
+ const token = urlObj.searchParams.get('token');
529
+ if (!token || !(await validateToken(token))) {
530
+ console.log('[supervisor] WS auth failed — rejecting');
531
+ socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
532
+ socket.destroy();
533
+ return;
534
+ }
535
+ }
543
536
 
544
- proxy.on('error', () => { console.error(`[supervisor] WS proxy error :${targetPort}`); socket.destroy(); });
545
- socket.on('error', () => proxy.destroy());
537
+ console.log('[supervisor] → Fluxy chat WebSocket');
538
+ fluxyWss.handleUpgrade(req, socket, head, (ws) => fluxyWss.emit('connection', ws, req));
546
539
  });
547
540
 
548
541
  // Start
@@ -1,17 +1,18 @@
1
1
  import { createServer as createViteServer, type ViteDevServer } from 'vite';
2
+ import type http from 'http';
2
3
  import path from 'path';
3
4
  import { PKG_DIR } from '../shared/paths.js';
4
5
  import { log } from '../shared/logger.js';
5
6
 
6
7
  let dashboardVite: ViteDevServer | null = null;
7
8
 
8
- export async function startViteDevServers(supervisorPort: number): Promise<{ dashboard: number }> {
9
+ export async function startViteDevServers(supervisorPort: number, hmrServer: http.Server): Promise<{ dashboard: number }> {
9
10
  const ports = {
10
11
  dashboard: supervisorPort + 2,
11
12
  };
12
13
 
13
14
  console.log(`[vite-dev] Starting dashboard Vite dev server on :${ports.dashboard}`);
14
- console.log(`[vite-dev] HMR clientPort :${supervisorPort} (browser connects through supervisor proxy)`);
15
+ console.log(`[vite-dev] HMR attached to supervisor server (port ${supervisorPort})`);
15
16
  console.log(`[vite-dev] PKG_DIR = ${PKG_DIR}`);
16
17
 
17
18
  try {
@@ -22,7 +23,7 @@ export async function startViteDevServers(supervisorPort: number): Promise<{ das
22
23
  host: '127.0.0.1',
23
24
  strictPort: true,
24
25
  allowedHosts: true,
25
- hmr: { clientPort: supervisorPort },
26
+ hmr: { server: hmrServer, clientPort: supervisorPort },
26
27
  },
27
28
  logLevel: 'info',
28
29
  });