fluxy-bot 0.8.9 → 0.8.10

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.
@@ -1,32 +1,173 @@
1
1
  import { Command } from 'commander';
2
- import { safeLoadConfig, pkg, DATA_DIR, createConfig } from '../core/config.js';
2
+ import { spinner } from '@clack/prompts';
3
+ import pc from 'picocolors';
3
4
  import fs from 'node:fs';
4
5
  import path from 'node:path';
5
- import pc from 'picocolors';
6
- import { runTunnelSetup } from './tunnel.js';
6
+ import os from 'node:os';
7
+ import { spawnSync } from 'node:child_process';
8
+
9
+ import { loadConfig, createConfig, CONFIG_PATH, DATA_DIR, pkg } from '../core/config.ts';
10
+ import { getAdapter } from '../platforms/index.ts';
11
+ import { banner } from '../utils/ui.ts';
12
+ import { bootServer } from '../core/server.ts';
13
+ import { CloudflaredManager } from '../core/cloudflared.ts';
14
+ import { runTunnelSetup } from './tunnel.ts';
7
15
 
8
16
  export function registerInitCommand(program: Command) {
9
17
  program
10
18
  .command('init')
11
19
  .description('Initialize Fluxy configuration')
12
20
  .action(async () => {
13
- createConfig(); // Creates it if missing
21
+ banner();
22
+
23
+ // ── Step 1: Create config ──
24
+ createConfig();
14
25
  fs.mkdirSync(DATA_DIR, { recursive: true });
15
26
  fs.writeFileSync(
16
27
  path.join(DATA_DIR, '.version'),
17
28
  pkg.version || '1.0.0'
18
29
  );
19
30
 
20
- console.log(pc.green('✓ Initialized base config.\n'));
31
+ // ── Step 2: Tunnel mode selection ──
32
+ const tunnelMode = await runTunnelSetup();
33
+
34
+ const config = loadConfig();
35
+ const hasTunnel = config.tunnel?.mode !== 'off';
36
+ const adapter = getAdapter();
37
+
38
+ // ── Step 3: Install cloudflared ──
39
+ if (hasTunnel && config.tunnel?.mode !== 'named') {
40
+ const s1 = spinner();
41
+ s1.start('Installing cloudflared...');
42
+ CloudflaredManager.install();
43
+ s1.stop(pc.green('Cloudflared ready'));
44
+ }
45
+
46
+ // ── Step 4: Boot server ──
47
+ const s = spinner();
48
+ s.start('Starting server...');
49
+
50
+ let result;
51
+ try {
52
+ result = await bootServer({
53
+ onTunnelUp: hasTunnel
54
+ ? url => {
55
+ s.message(
56
+ url
57
+ ? `Tunnel connected: ${pc.blue(url)}`
58
+ : 'Connecting tunnel...'
59
+ );
60
+ }
61
+ : undefined,
62
+ onReady: () => {
63
+ s.message('Preparing dashboard...');
64
+ }
65
+ });
66
+ } catch (err: any) {
67
+ s.stop(pc.red('Failed to start server'));
68
+ console.error(` ${err.message}`);
69
+ process.exit(1);
70
+ }
71
+
72
+ let { child, tunnelUrl, relayUrl, tunnelFailed, viteWarm } = result;
73
+
74
+ // ── Step 5: Wait for Vite warmup ──
75
+ s.message('Preparing dashboard...');
76
+ await Promise.race([viteWarm, new Promise(r => setTimeout(r, 30_000))]);
21
77
 
22
- await runTunnelSetup();
78
+ // ── Step 6: Install daemon (if supported) ──
79
+ if (adapter.hasDaemonSupport) {
80
+ s.message('Installing auto-start daemon...');
81
+
82
+ // Kill the temp server — daemon will start its own
83
+ child.kill('SIGTERM');
84
+ await new Promise(r => setTimeout(r, 1000));
85
+
86
+ const res = spawnSync(
87
+ process.execPath,
88
+ [process.argv[1], 'daemon', 'install'],
89
+ {
90
+ stdio: 'pipe',
91
+ env: {
92
+ ...process.env,
93
+ FLUXY_NODE_PATH: process.execPath,
94
+ FLUXY_REAL_HOME: os.homedir()
95
+ }
96
+ }
97
+ );
98
+
99
+ // Wait for the daemon's supervisor to get a new tunnel URL
100
+ if (res.status === 0 && hasTunnel) {
101
+ for (let i = 0; i < 30; i++) {
102
+ await new Promise(r => setTimeout(r, 1000));
103
+ try {
104
+ const cfg = JSON.parse(
105
+ fs.readFileSync(CONFIG_PATH, 'utf-8')
106
+ );
107
+ if (cfg.tunnelUrl && cfg.tunnelUrl !== tunnelUrl) {
108
+ tunnelUrl = cfg.tunnelUrl;
109
+ break;
110
+ }
111
+ } catch {}
112
+ }
113
+ // Pick up relay URL
114
+ try {
115
+ const cfg = JSON.parse(
116
+ fs.readFileSync(CONFIG_PATH, 'utf-8')
117
+ );
118
+ if (cfg.relay?.url) relayUrl = cfg.relay.url;
119
+ } catch {}
120
+ }
121
+
122
+ s.stop(pc.green('Fluxy is ready'));
123
+
124
+ if (res.status === 0) {
125
+ console.log(
126
+ `\n ${pc.blue('✔')} Daemon installed — Fluxy will auto-start on ${os.platform() === 'darwin' ? 'login' : 'boot'}.`
127
+ );
128
+ } else {
129
+ console.log(
130
+ `\n ${pc.yellow('⚠')} Daemon install failed. Run ${pc.magenta('fluxy daemon install')} manually.`
131
+ );
132
+ }
133
+ } else {
134
+ s.stop(pc.green('Server running'));
135
+ }
136
+
137
+ // ── Final message ──
138
+ console.log(`\n${pc.bold('Fluxy is ready!')}\n`);
23
139
 
24
140
  console.log(
25
- pc.dim(
26
- 'Run ' +
27
- pc.magenta('fluxy start') +
28
- ' to launch the server.'
29
- )
141
+ ` ${pc.dim('Local:')} ${pc.blue(`http://localhost:${config.port || 3000}`)}`
30
142
  );
143
+
144
+ if (hasTunnel && tunnelUrl && !tunnelFailed) {
145
+ console.log(
146
+ ` ${pc.dim('Tunnel:')} ${pc.blue(tunnelUrl)}`
147
+ );
148
+ }
149
+
150
+ if (relayUrl) {
151
+ console.log(
152
+ ` ${pc.dim('Relay:')} ${pc.blue(relayUrl)}`
153
+ );
154
+ }
155
+
156
+ if (tunnelFailed) {
157
+ console.log(
158
+ `\n ${pc.yellow('⚠')} Tunnel failed to connect.`
159
+ );
160
+ console.log(
161
+ ` ${pc.dim('Your bot is accessible on the local network at the URL above.')}`
162
+ );
163
+ }
164
+
165
+ if (!adapter.hasDaemonSupport) {
166
+ console.log(`\n ${pc.dim('Press Ctrl+C to stop')}\n`);
167
+ // Keep process alive
168
+ await new Promise(() => {});
169
+ } else {
170
+ console.log('');
171
+ }
31
172
  });
32
173
  }
@@ -57,10 +57,16 @@ export function bootServer({
57
57
  config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
58
58
  }
59
59
 
60
+ // Fallback: supervisor writes tunnelUrl to config.json
61
+ // even if we missed the stdout signal
62
+ const finalTunnelUrl =
63
+ tunnelUrl ||
64
+ (config as any).tunnelUrl ||
65
+ `http://localhost:${config.port || 3000}`;
66
+
60
67
  resolve({
61
68
  child,
62
- tunnelUrl:
63
- tunnelUrl || `http://localhost:${config.port || 3000}`,
69
+ tunnelUrl: finalTunnelUrl,
64
70
  relayUrl: relayUrl || config.relay?.url || null,
65
71
  tunnelFailed,
66
72
  viteWarm
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
3
  "description": "Self-hosted, self-evolving AI agent with its own dashboard.",
4
- "version": "0.8.9",
4
+ "version": "0.8.10",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "keywords": [