fluxy-bot 0.5.66 → 0.5.69

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
@@ -22,6 +22,9 @@ const [, , command, subcommand] = process.argv;
22
22
 
23
23
  // ── Daemon constants & helpers ──
24
24
 
25
+ const PLATFORM = os.platform();
26
+
27
+ // --- systemd (Linux) ---
25
28
  const SERVICE_NAME = 'fluxy';
26
29
  const SERVICE_PATH = `/etc/systemd/system/${SERVICE_NAME}.service`;
27
30
 
@@ -82,6 +85,105 @@ WantedBy=multi-user.target
82
85
  `;
83
86
  }
84
87
 
88
+ // --- launchd (macOS) ---
89
+ const LAUNCHD_LABEL = 'com.fluxy.bot';
90
+ const LAUNCHD_PLIST_PATH = path.join(os.homedir(), 'Library', 'LaunchAgents', `${LAUNCHD_LABEL}.plist`);
91
+ const LAUNCHD_LOG_DIR = path.join(os.homedir(), 'Library', 'Logs', 'fluxy');
92
+
93
+ function isLaunchdInstalled() {
94
+ return fs.existsSync(LAUNCHD_PLIST_PATH);
95
+ }
96
+
97
+ function isLaunchdActive() {
98
+ try {
99
+ const out = execSync(`launchctl list ${LAUNCHD_LABEL} 2>/dev/null`, { encoding: 'utf-8' });
100
+ // launchctl list <label> succeeds if the job is loaded; check PID field
101
+ const pidLine = out.split('\n').find(l => l.includes('PID'));
102
+ if (pidLine) {
103
+ const pid = pidLine.split('=')[1]?.trim();
104
+ return pid && pid !== '0' && pid !== '-';
105
+ }
106
+ // Fallback: if the command succeeded, it's loaded. Check if the process is running.
107
+ const lines = out.trim().split('\n');
108
+ // First line of `launchctl list <label>` output: "PID\tStatus\tLabel" header or direct values
109
+ // The format is: { "PID" = <pid>; "Status" = <code>; ... }
110
+ return !out.includes('"PID" = 0;');
111
+ } catch {
112
+ return false;
113
+ }
114
+ }
115
+
116
+ function generateLaunchdPlist({ nodePath, dataDir }) {
117
+ const nodeBinDir = path.dirname(nodePath);
118
+ fs.mkdirSync(LAUNCHD_LOG_DIR, { recursive: true });
119
+ return `<?xml version="1.0" encoding="UTF-8"?>
120
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
121
+ <plist version="1.0">
122
+ <dict>
123
+ <key>Label</key>
124
+ <string>${LAUNCHD_LABEL}</string>
125
+ <key>ProgramArguments</key>
126
+ <array>
127
+ <string>${nodePath}</string>
128
+ <string>--import</string>
129
+ <string>tsx/esm</string>
130
+ <string>${dataDir}/supervisor/index.ts</string>
131
+ </array>
132
+ <key>WorkingDirectory</key>
133
+ <string>${dataDir}</string>
134
+ <key>EnvironmentVariables</key>
135
+ <dict>
136
+ <key>HOME</key>
137
+ <string>${os.homedir()}</string>
138
+ <key>NODE_ENV</key>
139
+ <string>development</string>
140
+ <key>NODE_PATH</key>
141
+ <string>${dataDir}/node_modules</string>
142
+ <key>PATH</key>
143
+ <string>${nodeBinDir}:${dataDir}/node_modules/.bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
144
+ </dict>
145
+ <key>RunAtLoad</key>
146
+ <true/>
147
+ <key>KeepAlive</key>
148
+ <dict>
149
+ <key>SuccessfulExit</key>
150
+ <false/>
151
+ </dict>
152
+ <key>ThrottleInterval</key>
153
+ <integer>5</integer>
154
+ <key>StandardOutPath</key>
155
+ <string>${LAUNCHD_LOG_DIR}/stdout.log</string>
156
+ <key>StandardErrorPath</key>
157
+ <string>${LAUNCHD_LOG_DIR}/stderr.log</string>
158
+ <key>ProcessType</key>
159
+ <string>Standard</string>
160
+ </dict>
161
+ </plist>
162
+ `;
163
+ }
164
+
165
+ // --- Platform-agnostic daemon helpers ---
166
+
167
+ function hasDaemonSupport() {
168
+ if (PLATFORM === 'darwin') return true; // launchd is always available on macOS
169
+ if (PLATFORM === 'linux') {
170
+ try { execSync('systemctl --version', { stdio: 'ignore' }); return true; } catch { return false; }
171
+ }
172
+ return false;
173
+ }
174
+
175
+ function isDaemonInstalled() {
176
+ if (PLATFORM === 'darwin') return isLaunchdInstalled();
177
+ if (PLATFORM === 'linux') return isServiceInstalled();
178
+ return false;
179
+ }
180
+
181
+ function isDaemonActive() {
182
+ if (PLATFORM === 'darwin') return isLaunchdActive();
183
+ if (PLATFORM === 'linux') return isServiceActive();
184
+ return false;
185
+ }
186
+
85
187
  function killAndWait(child, timeout = 10_000) {
86
188
  return new Promise((resolve) => {
87
189
  child.removeAllListeners('exit');
@@ -663,8 +765,7 @@ async function init() {
663
765
  }
664
766
  fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
665
767
 
666
- const isLinux = os.platform() === 'linux';
667
- const hasSystemd = isLinux && (() => { try { execSync('systemctl --version', { stdio: 'ignore' }); return true; } catch { return false; } })();
768
+ const canDaemon = hasDaemonSupport();
668
769
 
669
770
  const steps = [
670
771
  'Creating config',
@@ -673,7 +774,7 @@ async function init() {
673
774
  'Connecting tunnel',
674
775
  'Verifying connection',
675
776
  'Preparing dashboard',
676
- ...(hasSystemd ? ['Setting up auto-start daemon'] : []),
777
+ ...(canDaemon ? ['Setting up auto-start daemon'] : []),
677
778
  ];
678
779
 
679
780
  const stepper = new Stepper(steps);
@@ -720,8 +821,8 @@ async function init() {
720
821
  await Promise.race([viteWarm, new Promise(r => setTimeout(r, 30_000))]);
721
822
  stepper.advance();
722
823
 
723
- // Install systemd daemon on Linux
724
- if (hasSystemd) {
824
+ // Install daemon (systemd on Linux, launchd on macOS)
825
+ if (canDaemon) {
725
826
  await killAndWait(child);
726
827
  const nodePath = process.execPath;
727
828
  const realHome = os.homedir();
@@ -737,7 +838,7 @@ async function init() {
737
838
  finalMessage(tunnelUrl, relayUrl);
738
839
  }
739
840
  if (res.status === 0) {
740
- console.log(` ${c.blue}✔${c.reset} Daemon installed — Fluxy will auto-start on boot.`);
841
+ console.log(` ${c.blue}✔${c.reset} Daemon installed — Fluxy will auto-start on ${PLATFORM === 'darwin' ? 'login' : 'boot'}.`);
741
842
  } else {
742
843
  console.log(` ${c.yellow}⚠${c.reset} Daemon install failed. Run ${c.pink}fluxy daemon install${c.reset} manually.`);
743
844
  }
@@ -768,7 +869,7 @@ async function start() {
768
869
  }
769
870
 
770
871
  // If daemon is already running, don't start a second instance
771
- if (os.platform() === 'linux' && isServiceInstalled() && isServiceActive()) {
872
+ if (isDaemonInstalled() && isDaemonActive()) {
772
873
  banner();
773
874
  const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
774
875
  console.log(`\n ${c.blue}●${c.reset} Fluxy is already running as a daemon.\n`);
@@ -782,9 +883,8 @@ async function start() {
782
883
  return;
783
884
  }
784
885
 
785
- const isLinux = os.platform() === 'linux';
786
- const hasSystemd = isLinux && (() => { try { execSync('systemctl --version', { stdio: 'ignore' }); return true; } catch { return false; } })();
787
- const needsDaemon = hasSystemd && !isServiceInstalled();
886
+ const canDaemon = hasDaemonSupport();
887
+ const needsDaemon = canDaemon && !isDaemonInstalled();
788
888
 
789
889
  banner();
790
890
 
@@ -836,7 +936,7 @@ async function start() {
836
936
  await Promise.race([viteWarm, new Promise(r => setTimeout(r, 30_000))]);
837
937
  stepper.advance();
838
938
 
839
- // Install systemd daemon on Linux if not already installed
939
+ // Install daemon (systemd on Linux, launchd on macOS) if not already installed
840
940
  if (needsDaemon) {
841
941
  await killAndWait(child);
842
942
  const nodePath = process.execPath;
@@ -853,7 +953,7 @@ async function start() {
853
953
  finalMessage(tunnelUrl, relayUrl);
854
954
  }
855
955
  if (res.status === 0) {
856
- console.log(` ${c.blue}✔${c.reset} Daemon installed — Fluxy will auto-start on boot.`);
956
+ console.log(` ${c.blue}✔${c.reset} Daemon installed — Fluxy will auto-start on ${PLATFORM === 'darwin' ? 'login' : 'boot'}.`);
857
957
  } else {
858
958
  console.log(` ${c.yellow}⚠${c.reset} Daemon install failed. Run ${c.pink}fluxy daemon install${c.reset} manually.`);
859
959
  }
@@ -880,7 +980,7 @@ async function start() {
880
980
 
881
981
  async function status() {
882
982
  const config = fs.existsSync(CONFIG_PATH) ? JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8')) : null;
883
- const daemonRunning = os.platform() === 'linux' && isServiceInstalled() && isServiceActive();
983
+ const daemonRunning = isDaemonInstalled() && isDaemonActive();
884
984
 
885
985
  // Try health endpoint
886
986
  let healthOk = false;
@@ -919,7 +1019,7 @@ async function update() {
919
1019
  // Refuse to run the update as root — file ownership would get poisoned
920
1020
  if (os.platform() !== 'win32' && process.getuid?.() === 0) {
921
1021
  console.log(`\n ${c.red}✗${c.reset} Do not run ${c.bold}fluxy update${c.reset} with sudo.`);
922
- console.log(` The update manages sudo internally for systemctl commands.\n`);
1022
+ console.log(` The update manages sudo internally for daemon commands.\n`);
923
1023
  process.exit(1);
924
1024
  }
925
1025
 
@@ -945,7 +1045,7 @@ async function update() {
945
1045
 
946
1046
  console.log(` ${c.dim}v${currentVersion} → v${latest.version}${c.reset}\n`);
947
1047
 
948
- const daemonWasRunning = os.platform() === 'linux' && isServiceInstalled() && isServiceActive();
1048
+ const daemonWasRunning = isDaemonInstalled() && isDaemonActive();
949
1049
 
950
1050
  const steps = [
951
1051
  ...(daemonWasRunning ? ['Stopping daemon'] : []),
@@ -962,8 +1062,12 @@ async function update() {
962
1062
  // Stop daemon before updating files
963
1063
  if (daemonWasRunning) {
964
1064
  try {
965
- const cmd = needsSudo() ? `sudo systemctl stop ${SERVICE_NAME}` : `systemctl stop ${SERVICE_NAME}`;
966
- execSync(cmd, { stdio: 'ignore' });
1065
+ if (PLATFORM === 'darwin') {
1066
+ execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}"`, { stdio: 'ignore' });
1067
+ } else {
1068
+ const cmd = needsSudo() ? `sudo systemctl stop ${SERVICE_NAME}` : `systemctl stop ${SERVICE_NAME}`;
1069
+ execSync(cmd, { stdio: 'ignore' });
1070
+ }
967
1071
  } catch {}
968
1072
  stepper.advance();
969
1073
  }
@@ -1053,8 +1157,12 @@ async function update() {
1053
1157
  // Restart daemon if it was running
1054
1158
  if (daemonWasRunning) {
1055
1159
  try {
1056
- const cmd = needsSudo() ? `sudo systemctl start ${SERVICE_NAME}` : `systemctl start ${SERVICE_NAME}`;
1057
- execSync(cmd, { stdio: 'ignore' });
1160
+ if (PLATFORM === 'darwin') {
1161
+ execSync(`launchctl load "${LAUNCHD_PLIST_PATH}"`, { stdio: 'ignore' });
1162
+ } else {
1163
+ const cmd = needsSudo() ? `sudo systemctl start ${SERVICE_NAME}` : `systemctl start ${SERVICE_NAME}`;
1164
+ execSync(cmd, { stdio: 'ignore' });
1165
+ }
1058
1166
  } catch {}
1059
1167
  stepper.advance();
1060
1168
  }
@@ -1073,15 +1181,19 @@ async function update() {
1073
1181
  }
1074
1182
 
1075
1183
  if (daemonWasRunning) {
1076
- if (isServiceActive()) {
1184
+ if (isDaemonActive()) {
1077
1185
  console.log(` ${c.blue}✔${c.reset} Daemon restarted with new version.\n`);
1078
1186
  } else {
1079
1187
  console.log(` ${c.yellow}⚠${c.reset} Daemon may still be starting. Check ${c.pink}fluxy daemon status${c.reset}\n`);
1080
1188
  }
1081
- } else if (os.platform() === 'linux' && isServiceInstalled()) {
1189
+ } else if (isDaemonInstalled()) {
1082
1190
  try {
1083
- const cmd = needsSudo() ? `sudo systemctl start ${SERVICE_NAME}` : `systemctl start ${SERVICE_NAME}`;
1084
- execSync(cmd, { stdio: 'ignore' });
1191
+ if (PLATFORM === 'darwin') {
1192
+ execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null; launchctl load "${LAUNCHD_PLIST_PATH}"`, { stdio: 'ignore' });
1193
+ } else {
1194
+ const cmd = needsSudo() ? `sudo systemctl start ${SERVICE_NAME}` : `systemctl start ${SERVICE_NAME}`;
1195
+ execSync(cmd, { stdio: 'ignore' });
1196
+ }
1085
1197
  console.log(` ${c.blue}✔${c.reset} Daemon started with new version.\n`);
1086
1198
  } catch {
1087
1199
  console.log(` ${c.dim}Run ${c.reset}${c.pink}fluxy daemon start${c.reset}${c.dim} to launch.${c.reset}\n`);
@@ -1095,15 +1207,131 @@ async function update() {
1095
1207
 
1096
1208
  async function daemon(sub) {
1097
1209
  // Platform guard
1098
- if (os.platform() !== 'linux') {
1099
- const hint = os.platform() === 'darwin'
1100
- ? 'Use tmux or nohup to keep Fluxy running in the background.'
1101
- : 'Use Task Scheduler to keep Fluxy running in the background.';
1102
- console.log(`\n ${c.yellow}⚠${c.reset} Daemon mode is only supported on Linux with systemd.`);
1210
+ if (!hasDaemonSupport()) {
1211
+ const hint = PLATFORM === 'win32'
1212
+ ? 'Use Task Scheduler to keep Fluxy running in the background.'
1213
+ : 'No supported daemon system found.';
1214
+ console.log(`\n ${c.yellow}⚠${c.reset} Daemon mode is not supported on this platform.`);
1103
1215
  console.log(` ${c.dim}${hint}${c.reset}\n`);
1104
1216
  process.exit(1);
1105
1217
  }
1106
1218
 
1219
+ const action = sub || 'install';
1220
+
1221
+ // ── macOS (launchd) ──
1222
+ if (PLATFORM === 'darwin') {
1223
+ switch (action) {
1224
+ case 'install': {
1225
+ const dataDir = path.join(os.homedir(), '.fluxy');
1226
+ if (!fs.existsSync(path.join(dataDir, 'supervisor', 'index.ts'))) {
1227
+ console.log(`\n ${c.red}✗${c.reset} Run ${c.pink}fluxy init${c.reset} first.\n`);
1228
+ process.exit(1);
1229
+ }
1230
+
1231
+ // Unload existing plist if loaded
1232
+ if (isLaunchdInstalled()) {
1233
+ try { execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, { stdio: 'ignore' }); } catch {}
1234
+ }
1235
+
1236
+ const nodePath = process.env.FLUXY_NODE_PATH || process.execPath;
1237
+ const plist = generateLaunchdPlist({ nodePath, dataDir });
1238
+
1239
+ // Ensure LaunchAgents directory exists
1240
+ fs.mkdirSync(path.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
1241
+ fs.writeFileSync(LAUNCHD_PLIST_PATH, plist);
1242
+ execSync(`launchctl load "${LAUNCHD_PLIST_PATH}"`, { stdio: 'ignore' });
1243
+
1244
+ // Verify it started
1245
+ await new Promise((r) => setTimeout(r, 2000));
1246
+ if (isLaunchdActive()) {
1247
+ console.log(`\n ${c.blue}✔${c.reset} Fluxy daemon installed and running.`);
1248
+ console.log(` ${c.dim}It will auto-start on login.${c.reset}`);
1249
+ console.log(`\n ${c.dim}View logs:${c.reset} ${c.pink}fluxy daemon logs${c.reset}`);
1250
+ console.log(` ${c.dim}Stop:${c.reset} ${c.pink}fluxy daemon stop${c.reset}`);
1251
+ console.log(` ${c.dim}Uninstall:${c.reset} ${c.pink}fluxy daemon uninstall${c.reset}\n`);
1252
+ } else {
1253
+ console.log(`\n ${c.yellow}⚠${c.reset} Plist installed but process may not be running.`);
1254
+ console.log(` ${c.dim}Check with: ${c.reset}${c.pink}fluxy daemon status${c.reset}\n`);
1255
+ }
1256
+ break;
1257
+ }
1258
+
1259
+ case 'stop': {
1260
+ if (!isLaunchdInstalled()) {
1261
+ console.log(`\n ${c.yellow}⚠${c.reset} Daemon not installed. Run ${c.pink}fluxy daemon install${c.reset} first.\n`);
1262
+ process.exit(1);
1263
+ }
1264
+ execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}"`, { stdio: 'ignore' });
1265
+ console.log(`\n ${c.blue}✔${c.reset} Fluxy daemon stopped.\n`);
1266
+ break;
1267
+ }
1268
+
1269
+ case 'start': {
1270
+ if (!isLaunchdInstalled()) {
1271
+ console.log(`\n ${c.yellow}⚠${c.reset} Daemon not installed. Run ${c.pink}fluxy daemon install${c.reset} first.\n`);
1272
+ process.exit(1);
1273
+ }
1274
+ // Reload: unload first in case it's already loaded, then load
1275
+ try { execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, { stdio: 'ignore' }); } catch {}
1276
+ execSync(`launchctl load "${LAUNCHD_PLIST_PATH}"`, { stdio: 'ignore' });
1277
+ console.log(`\n ${c.blue}✔${c.reset} Fluxy daemon started.\n`);
1278
+ break;
1279
+ }
1280
+
1281
+ case 'restart': {
1282
+ if (!isLaunchdInstalled()) {
1283
+ console.log(`\n ${c.yellow}⚠${c.reset} Daemon not installed. Run ${c.pink}fluxy daemon install${c.reset} first.\n`);
1284
+ process.exit(1);
1285
+ }
1286
+ try { execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, { stdio: 'ignore' }); } catch {}
1287
+ execSync(`launchctl load "${LAUNCHD_PLIST_PATH}"`, { stdio: 'ignore' });
1288
+ console.log(`\n ${c.blue}✔${c.reset} Fluxy daemon restarted.\n`);
1289
+ break;
1290
+ }
1291
+
1292
+ case 'status': {
1293
+ if (!isLaunchdInstalled()) {
1294
+ console.log(`\n ${c.dim}●${c.reset} Daemon not installed.\n`);
1295
+ break;
1296
+ }
1297
+ const active = isLaunchdActive();
1298
+ if (active) {
1299
+ console.log(`\n ${c.blue}●${c.reset} Fluxy daemon is running.`);
1300
+ } else {
1301
+ console.log(`\n ${c.dim}●${c.reset} Fluxy daemon is stopped.`);
1302
+ }
1303
+ console.log(` ${c.dim}Plist:${c.reset} ${LAUNCHD_PLIST_PATH}`);
1304
+ console.log(` ${c.dim}Logs:${c.reset} ${LAUNCHD_LOG_DIR}/\n`);
1305
+ break;
1306
+ }
1307
+
1308
+ case 'logs': {
1309
+ const logFile = path.join(LAUNCHD_LOG_DIR, 'stdout.log');
1310
+ if (!fs.existsSync(logFile)) {
1311
+ console.log(`\n ${c.dim}No logs found at ${logFile}${c.reset}\n`);
1312
+ break;
1313
+ }
1314
+ spawnSync('tail', ['-f', '-n', '50', logFile], { stdio: 'inherit' });
1315
+ break;
1316
+ }
1317
+
1318
+ case 'uninstall': {
1319
+ try { execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, { stdio: 'ignore' }); } catch {}
1320
+ if (fs.existsSync(LAUNCHD_PLIST_PATH)) fs.unlinkSync(LAUNCHD_PLIST_PATH);
1321
+ console.log(`\n ${c.blue}✔${c.reset} Fluxy daemon uninstalled.\n`);
1322
+ break;
1323
+ }
1324
+
1325
+ default:
1326
+ console.log(`\n ${c.red}✗${c.reset} Unknown daemon command: ${action}`);
1327
+ console.log(` ${c.dim}Available: install, start, stop, restart, status, logs, uninstall${c.reset}\n`);
1328
+ process.exit(1);
1329
+ }
1330
+ return;
1331
+ }
1332
+
1333
+ // ── Linux (systemd) ──
1334
+
1107
1335
  // Check systemd is available
1108
1336
  try {
1109
1337
  execSync('systemctl --version', { stdio: 'ignore' });
@@ -1112,8 +1340,6 @@ async function daemon(sub) {
1112
1340
  process.exit(1);
1113
1341
  }
1114
1342
 
1115
- const action = sub || 'install';
1116
-
1117
1343
  switch (action) {
1118
1344
  case 'install': {
1119
1345
  if (!fs.existsSync(path.join(getRealHome(), '.fluxy', 'supervisor', 'index.ts'))) {
@@ -1250,12 +1476,16 @@ async function tunnel(sub) {
1250
1476
  console.log(` ${c.blue}✔${c.reset} Fluxy config updated\n`);
1251
1477
 
1252
1478
  // Offer restart if daemon is running
1253
- if (os.platform() === 'linux' && isServiceInstalled() && isServiceActive()) {
1479
+ if (isDaemonInstalled() && isDaemonActive()) {
1254
1480
  const restart = await ask(` ${c.bold}Restart daemon now?${c.reset} ${c.dim}(Y/n)${c.reset}: `);
1255
1481
  if (!restart || restart.toLowerCase() === 'y') {
1256
1482
  try {
1257
- const cmd = needsSudo() ? `sudo systemctl restart ${SERVICE_NAME}` : `systemctl restart ${SERVICE_NAME}`;
1258
- execSync(cmd, { stdio: 'ignore' });
1483
+ if (PLATFORM === 'darwin') {
1484
+ execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null; launchctl load "${LAUNCHD_PLIST_PATH}"`, { stdio: 'ignore' });
1485
+ } else {
1486
+ const cmd = needsSudo() ? `sudo systemctl restart ${SERVICE_NAME}` : `systemctl restart ${SERVICE_NAME}`;
1487
+ execSync(cmd, { stdio: 'ignore' });
1488
+ }
1259
1489
  console.log(`\n ${c.blue}✔${c.reset} Daemon restarted.\n`);
1260
1490
  } catch {
1261
1491
  console.log(`\n ${c.yellow}⚠${c.reset} Restart failed. Try ${c.pink}fluxy daemon restart${c.reset}\n`);
@@ -1300,7 +1530,7 @@ async function tunnel(sub) {
1300
1530
  fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
1301
1531
  console.log(`\n ${c.blue}✔${c.reset} Tunnel mode reset to ${c.bold}quick${c.reset} (random trycloudflare.com URL).\n`);
1302
1532
 
1303
- if (os.platform() === 'linux' && isServiceInstalled() && isServiceActive()) {
1533
+ if (isDaemonInstalled() && isDaemonActive()) {
1304
1534
  console.log(` ${c.dim}Restart the daemon to apply: ${c.reset}${c.pink}fluxy daemon restart${c.reset}\n`);
1305
1535
  }
1306
1536
  break;