fluxy-bot 0.2.25 → 0.2.26
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 +1 -1
- package/scripts/install.sh +6 -1
- package/scripts/postinstall.js +11 -0
- package/supervisor/index.ts +51 -24
- package/supervisor/vite-dev.ts +9 -54
package/package.json
CHANGED
package/scripts/install.sh
CHANGED
|
@@ -69,9 +69,14 @@ ok "Files copied"
|
|
|
69
69
|
# ── Install dependencies ──
|
|
70
70
|
info "Installing dependencies (this may take a moment)..."
|
|
71
71
|
cd "$FLUXY_HOME"
|
|
72
|
-
npm install --omit=dev
|
|
72
|
+
npm install --omit=dev 2>/dev/null
|
|
73
73
|
ok "Dependencies installed"
|
|
74
74
|
|
|
75
|
+
# ── Build fluxy chat + onboard (served as static files) ──
|
|
76
|
+
info "Building chat interface..."
|
|
77
|
+
npm run build:fluxy 2>/dev/null
|
|
78
|
+
ok "Chat interface built"
|
|
79
|
+
|
|
75
80
|
# ── Create symlink ──
|
|
76
81
|
info "Creating fluxy command..."
|
|
77
82
|
chmod +x "$FLUXY_HOME/bin/cli.js"
|
package/scripts/postinstall.js
CHANGED
|
@@ -61,6 +61,17 @@ try {
|
|
|
61
61
|
// Non-fatal: deps may already exist from a previous install
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// ── Build fluxy chat + onboard (served as static files) ──
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
execSync('npm run build:fluxy', {
|
|
68
|
+
cwd: FLUXY_HOME,
|
|
69
|
+
stdio: 'ignore',
|
|
70
|
+
});
|
|
71
|
+
} catch {
|
|
72
|
+
// Non-fatal: will be built on first start if needed
|
|
73
|
+
}
|
|
74
|
+
|
|
64
75
|
// ── Create fluxy symlink ──
|
|
65
76
|
|
|
66
77
|
const cliPath = path.join(FLUXY_HOME, 'bin', 'cli.js');
|
package/supervisor/index.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import net from 'net';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
4
5
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
5
6
|
import { loadConfig, saveConfig } from '../shared/config.js';
|
|
6
7
|
import { createProvider, type AiProvider, type ChatMessage } from '../shared/ai.js';
|
|
7
8
|
import { paths } from '../shared/paths.js';
|
|
9
|
+
import { PKG_DIR } from '../shared/paths.js';
|
|
8
10
|
import { log } from '../shared/logger.js';
|
|
9
11
|
import { startTunnel, stopTunnel, isTunnelAlive, restartTunnel } from './tunnel.js';
|
|
10
12
|
import { spawnWorker, stopWorker, getWorkerPort, isWorkerAlive } from './worker.js';
|
|
@@ -12,6 +14,20 @@ import { updateTunnelUrl, startHeartbeat, stopHeartbeat, disconnect } from '../s
|
|
|
12
14
|
import { startFluxyAgentQuery, stopFluxyAgentQuery } from './fluxy-agent.js';
|
|
13
15
|
import { startViteDevServers, stopViteDevServers } from './vite-dev.js';
|
|
14
16
|
|
|
17
|
+
const DIST_FLUXY = path.join(PKG_DIR, 'dist-fluxy');
|
|
18
|
+
|
|
19
|
+
const MIME_TYPES: Record<string, string> = {
|
|
20
|
+
'.html': 'text/html',
|
|
21
|
+
'.js': 'application/javascript',
|
|
22
|
+
'.css': 'text/css',
|
|
23
|
+
'.png': 'image/png',
|
|
24
|
+
'.jpg': 'image/jpeg',
|
|
25
|
+
'.svg': 'image/svg+xml',
|
|
26
|
+
'.webm': 'video/webm',
|
|
27
|
+
'.woff2': 'font/woff2',
|
|
28
|
+
'.json': 'application/json',
|
|
29
|
+
};
|
|
30
|
+
|
|
15
31
|
const RECOVERING_HTML = `<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Recovering</title>
|
|
16
32
|
<style>body{background:#0a0a0f;color:#94a3b8;font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0}
|
|
17
33
|
div{text-align:center}h1{font-size:18px;margin-bottom:8px;color:#e2e8f0}p{font-size:14px}a{color:#60a5fa}</style></head>
|
|
@@ -23,10 +39,10 @@ export async function startSupervisor() {
|
|
|
23
39
|
const config = loadConfig();
|
|
24
40
|
const workerPort = getWorkerPort(config.port);
|
|
25
41
|
|
|
26
|
-
// Start Vite dev
|
|
27
|
-
console.log('[supervisor] Starting Vite dev
|
|
42
|
+
// Start Vite dev server for dashboard HMR
|
|
43
|
+
console.log('[supervisor] Starting Vite dev server...');
|
|
28
44
|
const vitePorts = await startViteDevServers(config.port);
|
|
29
|
-
console.log(`[supervisor] Vite ready — dashboard :${vitePorts.dashboard}
|
|
45
|
+
console.log(`[supervisor] Vite ready — dashboard :${vitePorts.dashboard}`);
|
|
30
46
|
|
|
31
47
|
// Fluxy's AI brain
|
|
32
48
|
let ai: AiProvider | null = null;
|
|
@@ -73,25 +89,37 @@ export async function startSupervisor() {
|
|
|
73
89
|
return;
|
|
74
90
|
}
|
|
75
91
|
|
|
76
|
-
// Fluxy routes →
|
|
92
|
+
// Fluxy routes → serve pre-built static files from dist-fluxy/
|
|
77
93
|
// Note: must check '/fluxy/' (with slash) to avoid matching '/fluxy_tilts.webm' etc.
|
|
78
94
|
if (req.url === '/fluxy' || req.url?.startsWith('/fluxy/')) {
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
// Strip /fluxy prefix and resolve file path
|
|
96
|
+
let filePath = req.url!.replace(/^\/fluxy\/?/, '') || 'fluxy.html';
|
|
97
|
+
// Strip query strings (e.g. ?v=xxx)
|
|
98
|
+
filePath = filePath.split('?')[0];
|
|
99
|
+
const fullPath = path.join(DIST_FLUXY, filePath);
|
|
100
|
+
|
|
101
|
+
// Security: prevent directory traversal
|
|
102
|
+
if (!fullPath.startsWith(DIST_FLUXY)) {
|
|
103
|
+
res.writeHead(403);
|
|
104
|
+
res.end('Forbidden');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const stat = fs.statSync(fullPath);
|
|
110
|
+
if (stat.isFile()) {
|
|
111
|
+
const ext = path.extname(fullPath);
|
|
112
|
+
const mime = MIME_TYPES[ext] || 'application/octet-stream';
|
|
113
|
+
res.writeHead(200, { 'Content-Type': mime, 'Cache-Control': 'public, max-age=31536000, immutable' });
|
|
114
|
+
fs.createReadStream(fullPath).pipe(res);
|
|
115
|
+
} else {
|
|
116
|
+
res.writeHead(404);
|
|
117
|
+
res.end('Not found');
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
res.writeHead(404);
|
|
121
|
+
res.end('Not found');
|
|
122
|
+
}
|
|
95
123
|
return;
|
|
96
124
|
}
|
|
97
125
|
|
|
@@ -213,10 +241,9 @@ export async function startSupervisor() {
|
|
|
213
241
|
return;
|
|
214
242
|
}
|
|
215
243
|
|
|
216
|
-
// Route HMR WebSocket to
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
console.log(`[supervisor] → Vite HMR (${isFluxy ? 'fluxy' : 'dashboard'}) :${targetPort}`);
|
|
244
|
+
// Route HMR WebSocket to dashboard Vite dev server
|
|
245
|
+
const targetPort = vitePorts.dashboard;
|
|
246
|
+
console.log(`[supervisor] → Vite HMR (dashboard) :${targetPort}`);
|
|
220
247
|
|
|
221
248
|
const proxy = net.connect(targetPort, () => {
|
|
222
249
|
const headers = Object.entries(req.headers).map(([k, v]) => `${k}: ${v}`).join('\r\n');
|
package/supervisor/vite-dev.ts
CHANGED
|
@@ -4,21 +4,16 @@ import { PKG_DIR } from '../shared/paths.js';
|
|
|
4
4
|
import { log } from '../shared/logger.js';
|
|
5
5
|
|
|
6
6
|
let dashboardVite: ViteDevServer | null = null;
|
|
7
|
-
let fluxyVite: ViteDevServer | null = null;
|
|
8
7
|
|
|
9
|
-
export async function startViteDevServers(supervisorPort: number): Promise<{ dashboard: number
|
|
8
|
+
export async function startViteDevServers(supervisorPort: number): Promise<{ dashboard: number }> {
|
|
10
9
|
const ports = {
|
|
11
10
|
dashboard: supervisorPort + 2,
|
|
12
|
-
fluxy: supervisorPort + 3,
|
|
13
11
|
};
|
|
14
12
|
|
|
15
|
-
console.log(`[vite-dev] Starting Vite dev
|
|
16
|
-
console.log(`[vite-dev] Dashboard → :${ports.dashboard}, Fluxy → :${ports.fluxy}`);
|
|
13
|
+
console.log(`[vite-dev] Starting dashboard Vite dev server on :${ports.dashboard}`);
|
|
17
14
|
console.log(`[vite-dev] HMR clientPort → :${supervisorPort} (browser connects through supervisor proxy)`);
|
|
18
15
|
console.log(`[vite-dev] PKG_DIR = ${PKG_DIR}`);
|
|
19
16
|
|
|
20
|
-
// Dashboard Vite dev server
|
|
21
|
-
console.log('[vite-dev] Creating dashboard Vite server...');
|
|
22
17
|
try {
|
|
23
18
|
dashboardVite = await createViteServer({
|
|
24
19
|
configFile: path.join(PKG_DIR, 'vite.config.ts'),
|
|
@@ -38,51 +33,16 @@ export async function startViteDevServers(supervisorPort: number): Promise<{ das
|
|
|
38
33
|
throw err;
|
|
39
34
|
}
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
console.log('[vite-dev] Creating fluxy Vite server...');
|
|
43
|
-
try {
|
|
44
|
-
fluxyVite = await createViteServer({
|
|
45
|
-
configFile: path.join(PKG_DIR, 'vite.fluxy.config.ts'),
|
|
46
|
-
server: {
|
|
47
|
-
port: ports.fluxy,
|
|
48
|
-
host: '127.0.0.1',
|
|
49
|
-
strictPort: true,
|
|
50
|
-
allowedHosts: true,
|
|
51
|
-
hmr: { clientPort: supervisorPort },
|
|
52
|
-
},
|
|
53
|
-
logLevel: 'info',
|
|
54
|
-
});
|
|
55
|
-
await fluxyVite.listen();
|
|
56
|
-
console.log(`[vite-dev] ✓ Fluxy Vite ready on :${ports.fluxy}`);
|
|
57
|
-
} catch (err) {
|
|
58
|
-
console.error('[vite-dev] ✗ Fluxy Vite failed:', err);
|
|
59
|
-
throw err;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
log.ok(`Vite HMR active — dashboard :${ports.dashboard}, fluxy :${ports.fluxy}`);
|
|
36
|
+
log.ok(`Vite HMR active — dashboard :${ports.dashboard}`);
|
|
63
37
|
|
|
64
|
-
// Warm up: fetch
|
|
65
|
-
|
|
66
|
-
Promise.all([
|
|
67
|
-
fetch(`http://127.0.0.1:${ports.dashboard}/`).then(r => r.text()),
|
|
68
|
-
fetch(`http://127.0.0.1:${ports.fluxy}/fluxy/fluxy.html`).then(r => r.text()),
|
|
69
|
-
fetch(`http://127.0.0.1:${ports.fluxy}/fluxy/onboard.html`).then(r => r.text()),
|
|
70
|
-
]).then(async ([dashHtml, fluxyHtml, onboardHtml]) => {
|
|
71
|
-
// Parse script entries and fetch them to trigger full module graph transformation
|
|
38
|
+
// Warm up: fetch the dashboard entry to pre-transform modules
|
|
39
|
+
fetch(`http://127.0.0.1:${ports.dashboard}/`).then(r => r.text()).then(async (html) => {
|
|
72
40
|
const scriptRe = /src="([^"]+\.tsx)"/g;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
[onboardHtml, ports.fluxy, '/fluxy'],
|
|
78
|
-
] as [string, number, string][]) {
|
|
79
|
-
let m;
|
|
80
|
-
while ((m = scriptRe.exec(html)) !== null) {
|
|
81
|
-
const url = `http://127.0.0.1:${port}${base}${m[1].startsWith('/') ? '' : '/'}${m[1]}`;
|
|
82
|
-
fetches.push(fetch(url).then(r => r.text()).catch(() => {}));
|
|
83
|
-
}
|
|
41
|
+
let m;
|
|
42
|
+
while ((m = scriptRe.exec(html)) !== null) {
|
|
43
|
+
const url = `http://127.0.0.1:${ports.dashboard}${m[1].startsWith('/') ? '' : '/'}${m[1]}`;
|
|
44
|
+
await fetch(url).then(r => r.text()).catch(() => {});
|
|
84
45
|
}
|
|
85
|
-
await Promise.all(fetches);
|
|
86
46
|
console.log('__VITE_WARM__');
|
|
87
47
|
}).catch(() => {
|
|
88
48
|
console.log('__VITE_WARM__');
|
|
@@ -98,9 +58,4 @@ export async function stopViteDevServers(): Promise<void> {
|
|
|
98
58
|
dashboardVite = null;
|
|
99
59
|
console.log('[vite-dev] Dashboard Vite stopped');
|
|
100
60
|
}
|
|
101
|
-
if (fluxyVite) {
|
|
102
|
-
await fluxyVite.close();
|
|
103
|
-
fluxyVite = null;
|
|
104
|
-
console.log('[vite-dev] Fluxy Vite stopped');
|
|
105
|
-
}
|
|
106
61
|
}
|