fluxy-bot 0.5.49 → 0.5.51

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 +1 @@
1
- import{b as o,j as e,R as n,O as r}from"./globals-B1nERNzb.js";function a(){const t=()=>{window.parent?.postMessage({type:"fluxy:onboard-complete"},"*")};return e.jsx(r,{onComplete:t,isInitialSetup:!0})}o.createRoot(document.getElementById("root")).render(e.jsx(n.StrictMode,{children:e.jsx(a,{})}));
1
+ import{b as o,j as e,R as n,O as r}from"./globals-USEW-jnB.js";function a(){const t=()=>{window.parent?.postMessage({type:"fluxy:onboard-complete"},"*")};return e.jsx(r,{onComplete:t,isInitialSetup:!0})}o.createRoot(document.getElementById("root")).render(e.jsx(n.StrictMode,{children:e.jsx(a,{})}));
@@ -2,11 +2,11 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
6
6
  <title>Fluxy Chat</title>
7
- <script type="module" crossorigin src="/fluxy/assets/fluxy-DbZm7HVX.js"></script>
8
- <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-B1nERNzb.js">
9
- <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-BHyeC8Bo.css">
7
+ <script type="module" crossorigin src="/fluxy/assets/fluxy-Dc1OmA8X.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-USEW-jnB.js">
9
+ <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-DkRInmdq.css">
10
10
  </head>
11
11
  <body class="bg-background text-foreground">
12
12
  <div id="root"></div>
@@ -2,11 +2,11 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
6
6
  <title>Fluxy Setup</title>
7
- <script type="module" crossorigin src="/fluxy/assets/onboard-bonnEh6v.js"></script>
8
- <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-B1nERNzb.js">
9
- <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-BHyeC8Bo.css">
7
+ <script type="module" crossorigin src="/fluxy/assets/onboard-EbXfpdmz.js"></script>
8
+ <link rel="modulepreload" crossorigin href="/fluxy/assets/globals-USEW-jnB.js">
9
+ <link rel="stylesheet" crossorigin href="/fluxy/assets/globals-DkRInmdq.css">
10
10
  </head>
11
11
  <body class="bg-background text-foreground">
12
12
  <div id="root"></div>
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.5.49",
3
+ "version": "0.5.51",
4
4
  "releaseNotes": [
5
- "1. ",
5
+ "Fixed some bugs to iOs ",
6
6
  "2. ",
7
7
  "3. ",
8
8
  "4. "
@@ -344,13 +344,30 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
344
344
 
345
345
  /* ── Auth handlers: Anthropic/Claude ── */
346
346
 
347
+ const openExternal = (url: string) => {
348
+ const isStandalone = window.matchMedia('(display-mode: standalone)').matches
349
+ || (navigator as any).standalone === true;
350
+ if (isStandalone) {
351
+ // iOS PWA standalone mode blocks window.open — use a temp anchor with target _blank
352
+ const a = document.createElement('a');
353
+ a.href = url;
354
+ a.target = '_blank';
355
+ a.rel = 'noopener noreferrer';
356
+ document.body.appendChild(a);
357
+ a.click();
358
+ document.body.removeChild(a);
359
+ } else {
360
+ window.open(url, '_blank', 'noopener,noreferrer');
361
+ }
362
+ };
363
+
347
364
  const handleAnthropicAuth = async () => {
348
365
  setAnthropicError(undefined);
349
366
  try {
350
367
  const res = await fetch('/api/auth/claude/start', { method: 'POST' });
351
368
  const data = await res.json();
352
369
  if (data.success && data.authUrl) {
353
- window.open(data.authUrl, '_blank');
370
+ openExternal(data.authUrl);
354
371
  setOauthStarted(true);
355
372
  } else {
356
373
  setAnthropicError(data.error || 'Failed to start authentication');
@@ -415,7 +432,7 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
415
432
  const res = await fetch('/api/auth/codex/start', { method: 'POST' });
416
433
  const data = await res.json();
417
434
  if (data.success && data.authUrl) {
418
- window.open(data.authUrl, '_blank');
435
+ openExternal(data.authUrl);
419
436
  } else {
420
437
  setOpenaiWaiting(false);
421
438
  setOpenaiError(data.error || 'Failed to start authentication');
@@ -956,8 +973,17 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
956
973
  {provider === 'anthropic' && (
957
974
  <div className="space-y-2.5">
958
975
  {isConnected && (
959
- <div className="bg-emerald-500/8 border border-emerald-500/15 rounded-lg px-3.5 py-2.5">
960
- <p className="text-emerald-400/90 text-[12px]">Connected Anthropic subscription is active.</p>
976
+ <div className="space-y-2.5">
977
+ <div className="bg-emerald-500/8 border border-emerald-500/15 rounded-lg px-3.5 py-2.5">
978
+ <p className="text-emerald-400/90 text-[12px]">Connected — Anthropic subscription is active.</p>
979
+ </div>
980
+ <button
981
+ onClick={() => { setAuthState((s) => ({ ...s, anthropic: 'idle' })); setOauthStarted(false); setAnthropicCode(''); setAnthropicError(''); }}
982
+ className="w-full py-1.5 text-white/25 text-[11px] hover:text-white/40 transition-colors flex items-center justify-center gap-1.5"
983
+ >
984
+ <RefreshCw className="h-3 w-3" />
985
+ Re-authenticate
986
+ </button>
961
987
  </div>
962
988
  )}
963
989
 
@@ -1039,8 +1065,17 @@ export default function OnboardWizard({ onComplete, isInitialSetup = false, onSa
1039
1065
  {provider === 'openai' && (
1040
1066
  <div className="space-y-2.5">
1041
1067
  {isConnected && (
1042
- <div className="bg-emerald-500/8 border border-emerald-500/15 rounded-lg px-3.5 py-2.5">
1043
- <p className="text-emerald-400/90 text-[12px]">Connected ChatGPT subscription is active.</p>
1068
+ <div className="space-y-2.5">
1069
+ <div className="bg-emerald-500/8 border border-emerald-500/15 rounded-lg px-3.5 py-2.5">
1070
+ <p className="text-emerald-400/90 text-[12px]">Connected — ChatGPT subscription is active.</p>
1071
+ </div>
1072
+ <button
1073
+ onClick={() => { setAuthState((s) => ({ ...s, openai: 'idle' })); setOpenaiError(''); }}
1074
+ className="w-full py-1.5 text-white/25 text-[11px] hover:text-white/40 transition-colors flex items-center justify-center gap-1.5"
1075
+ >
1076
+ <RefreshCw className="h-3 w-3" />
1077
+ Re-authenticate
1078
+ </button>
1044
1079
  </div>
1045
1080
  )}
1046
1081
 
@@ -2,7 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
6
6
  <title>Fluxy Chat</title>
7
7
  </head>
8
8
  <body class="bg-background text-foreground">
@@ -2,7 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
6
6
  <title>Fluxy Setup</title>
7
7
  </head>
8
8
  <body class="bg-background text-foreground">
@@ -38,11 +38,17 @@
38
38
  --radius: 0.75rem;
39
39
  }
40
40
 
41
+ html {
42
+ touch-action: manipulation;
43
+ -ms-touch-action: manipulation;
44
+ }
45
+
41
46
  body {
42
47
  background-color: var(--color-background);
43
48
  color: var(--color-foreground);
44
49
  -webkit-font-smoothing: antialiased;
45
50
  -moz-osx-font-smoothing: grayscale;
51
+ overscroll-behavior: none;
46
52
  }
47
53
 
48
54
  ::selection {
@@ -146,6 +146,7 @@ export async function startFluxyAgentQuery(
146
146
 
147
147
  let fullText = '';
148
148
  const usedTools = new Set<string>();
149
+ let stderrBuf = '';
149
150
 
150
151
  // If there are saved files but no inline attachments, append path info to plain text prompt
151
152
  let plainPrompt = prompt;
@@ -188,7 +189,6 @@ export async function startFluxyAgentQuery(
188
189
  }
189
190
  } catch {}
190
191
 
191
- let stderrBuf = '';
192
192
  const claudeQuery = query({
193
193
  prompt: sdkPrompt,
194
194
  options: {
@@ -762,36 +762,20 @@ export async function startSupervisor() {
762
762
  config.tunnelUrl = tunnelUrl;
763
763
  saveConfig(config);
764
764
 
765
- // Register tunnel URL with relay and start heartbeats
766
- if (config.relay?.token) {
767
- try {
768
- await updateTunnelUrl(config.relay.token, tunnelUrl);
769
- startHeartbeat(config.relay.token, tunnelUrl);
770
- if (config.relay.url) {
771
- log.ok(`Relay: ${config.relay.url}`);
772
- console.log(`__RELAY_URL__=${config.relay.url}`);
773
- }
774
- } catch (err) {
775
- log.warn(`Relay: ${err instanceof Error ? err.message : err}`);
776
- }
777
- }
778
-
779
- // Poll until the full relay→tunnel→server chain is actually working.
780
- // A 502/503 means the relay can't reach the tunnel yet; anything else
781
- // (200, 401, 403, etc.) means the chain is live.
782
- const probeUrl = config.relay?.url || tunnelUrl;
783
- let ready = false;
784
- log.info(`Readiness probe: polling ${probeUrl}`);
765
+ // Wait for the tunnel to be reachable before telling the relay about it.
766
+ // This prevents the relay from proxying traffic to a tunnel that isn't ready,
767
+ // which would cause 502s for users on the custom domain.
768
+ let tunnelReady = false;
769
+ log.info(`Readiness probe: waiting for tunnel ${tunnelUrl}`);
785
770
  for (let i = 0; i < 30; i++) {
786
771
  try {
787
- const res = await fetch(probeUrl + `/api/health?_cb=${Date.now()}`, {
772
+ const res = await fetch(tunnelUrl + `/api/health?_cb=${Date.now()}`, {
788
773
  signal: AbortSignal.timeout(3000),
789
774
  headers: { 'Cache-Control': 'no-cache, no-store' },
790
775
  });
791
776
  log.info(`Readiness probe #${i + 1}: ${res.status}`);
792
- // Any non-502/503 means the relay is reaching the tunnel
793
777
  if (res.status !== 502 && res.status !== 503) {
794
- ready = true;
778
+ tunnelReady = true;
795
779
  break;
796
780
  }
797
781
  } catch (err) {
@@ -799,8 +783,22 @@ export async function startSupervisor() {
799
783
  }
800
784
  await new Promise(r => setTimeout(r, 1000));
801
785
  }
802
- if (!ready) {
803
- log.warn('Readiness probe timed out — URL may not be reachable yet');
786
+ if (!tunnelReady) {
787
+ log.warn('Tunnel readiness probe timed out — updating relay anyway');
788
+ }
789
+
790
+ // Now register tunnel URL with relay and start heartbeats
791
+ if (config.relay?.token) {
792
+ try {
793
+ await updateTunnelUrl(config.relay.token, tunnelUrl);
794
+ startHeartbeat(config.relay.token, tunnelUrl);
795
+ if (config.relay.url) {
796
+ log.ok(`Relay: ${config.relay.url}`);
797
+ console.log(`__RELAY_URL__=${config.relay.url}`);
798
+ }
799
+ } catch (err) {
800
+ log.warn(`Relay: ${err instanceof Error ? err.message : err}`);
801
+ }
804
802
  }
805
803
  console.log('__READY__');
806
804
  } catch (err) {
@@ -826,6 +824,28 @@ export async function startSupervisor() {
826
824
  log.warn('Tunnel dead, restarting...');
827
825
  try {
828
826
  const newUrl = await restartTunnel(config.port);
827
+
828
+ // Wait for the new tunnel to be reachable before updating the relay
829
+ log.info(`Waiting for new tunnel to become reachable: ${newUrl}`);
830
+ let tunnelReady = false;
831
+ for (let i = 0; i < 30; i++) {
832
+ try {
833
+ const res = await fetch(newUrl + `/api/health?_cb=${Date.now()}`, {
834
+ signal: AbortSignal.timeout(3000),
835
+ headers: { 'Cache-Control': 'no-cache, no-store' },
836
+ });
837
+ if (res.status !== 502 && res.status !== 503) {
838
+ tunnelReady = true;
839
+ log.info(`Tunnel reachable after ${i + 1} probes`);
840
+ break;
841
+ }
842
+ } catch {}
843
+ await new Promise(r => setTimeout(r, 1000));
844
+ }
845
+ if (!tunnelReady) {
846
+ log.warn('Tunnel readiness probe timed out — updating relay anyway');
847
+ }
848
+
829
849
  tunnelUrl = newUrl;
830
850
  config.tunnelUrl = newUrl;
831
851
  saveConfig(config);
@@ -40,16 +40,28 @@
40
40
  bubble.setAttribute('role', 'button');
41
41
  bubble.setAttribute('aria-label', 'Open Fluxy chat');
42
42
 
43
- var video = document.createElement('video');
44
- video.src = '/fluxy_tilts.webm';
45
- video.poster = '/fluxy_frame1.png';
46
- video.autoplay = true;
47
- video.loop = true;
48
- video.muted = true;
49
- video.playsInline = true;
50
- video.setAttribute('playsinline', '');
51
- video.draggable = false;
52
- bubble.appendChild(video);
43
+ // Safari doesn't support WebM alpha — fall back to poster image
44
+ var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
45
+ || (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream);
46
+
47
+ if (isSafari) {
48
+ var img = document.createElement('img');
49
+ img.src = '/fluxy_frame1.png';
50
+ img.alt = 'Fluxy';
51
+ img.draggable = false;
52
+ bubble.appendChild(img);
53
+ } else {
54
+ var video = document.createElement('video');
55
+ video.src = '/fluxy_tilts.webm';
56
+ video.poster = '/fluxy_frame1.png';
57
+ video.autoplay = true;
58
+ video.loop = true;
59
+ video.muted = true;
60
+ video.playsInline = true;
61
+ video.setAttribute('playsinline', '');
62
+ video.draggable = false;
63
+ bubble.appendChild(video);
64
+ }
53
65
 
54
66
  // Mark widget present
55
67
  bubble.dataset.fluxyWidget = '1';
@@ -2,7 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, interactive-widget=resizes-content" />
6
6
  <meta name="theme-color" content="#212121" />
7
7
  <meta name="apple-mobile-web-app-capable" content="yes" />
8
8
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
@@ -22,7 +22,7 @@
22
22
  if (root && root.children.length === 0) {
23
23
  root.innerHTML =
24
24
  '<div style="background:#222122;color:#fff;display:flex;flex-direction:column;align-items:center;justify-content:center;height:100dvh;width:100vw;position:fixed;inset:0;z-index:50;font-family:system-ui,-apple-system,sans-serif;text-align:center;padding:24px">' +
25
- '<video src="/fluxy_say_hi.webm" autoplay loop muted playsinline style="height:120px;width:120px;border-radius:50%;object-fit:cover;margin-bottom:32px"></video>' +
25
+ '<img src="/fluxy_frame1.png" style="height:120px;width:120px;border-radius:50%;object-fit:cover;margin-bottom:32px" alt="Fluxy" />' +
26
26
  '<h1 style="font-size:20px;font-weight:600;margin-bottom:8px">Your app crashed</h1>' +
27
27
  '<p style="font-size:14px;color:rgba(255,255,255,0.5);max-width:320px;line-height:1.5">Ask the agent to fix it using the chat.</p>' +
28
28
  '</div>';
@@ -38,11 +38,17 @@
38
38
  --radius: 0.75rem;
39
39
  }
40
40
 
41
+ html {
42
+ touch-action: manipulation;
43
+ -ms-touch-action: manipulation;
44
+ }
45
+
41
46
  body {
42
47
  background-color: var(--color-background);
43
48
  color: var(--color-foreground);
44
49
  -webkit-font-smoothing: antialiased;
45
50
  -moz-osx-font-smoothing: grayscale;
51
+ overscroll-behavior: none;
46
52
  }
47
53
 
48
54
  ::selection {