fluxy-bot 0.1.45 → 0.2.0

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
@@ -8,10 +8,8 @@ import { fileURLToPath } from 'url';
8
8
 
9
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
10
 
11
+ const ROOT = path.resolve(__dirname, '..');
11
12
  const DATA_DIR = path.join(os.homedir(), '.fluxy');
12
- const APP_DIR = path.join(DATA_DIR, 'app');
13
- // Use ~/.fluxy/app/ if it exists (editable copy), otherwise fall back to npm install location
14
- const ROOT = fs.existsSync(APP_DIR) ? APP_DIR : path.resolve(__dirname, '..');
15
13
  const CONFIG_PATH = path.join(DATA_DIR, 'config.json');
16
14
  const BIN_DIR = path.join(DATA_DIR, 'bin');
17
15
  const CF_PATH = path.join(BIN_DIR, 'cloudflared');
@@ -6,8 +6,6 @@ import DashboardLayout from './components/Layout/DashboardLayout';
6
6
  import DashboardPage from './components/Dashboard/DashboardPage';
7
7
  import ChatView from './components/Chat/ChatView';
8
8
  import FluxyFab from './components/FluxyFab';
9
- import BuildOverlay from './components/BuildOverlay';
10
-
11
9
  import OnboardWizard from './components/Onboard/OnboardWizard';
12
10
  import {
13
11
  Sheet,
@@ -72,7 +70,6 @@ export default function App() {
72
70
  <>
73
71
  <ErrorBoundary fallback={<DashboardError />}>
74
72
  <DashboardLayout onOpenOnboard={() => setShowOnboard(true)}>
75
- <BuildOverlay ws={ws} />
76
73
  <DashboardPage />
77
74
  </DashboardLayout>
78
75
  </ErrorBoundary>
@@ -17,7 +17,7 @@ export default function DashboardLayout({ children, onOpenOnboard }: Props) {
17
17
  <Sidebar />
18
18
  </div>
19
19
  {/* Main content */}
20
- <main className="relative flex-1 overflow-y-auto p-4 md:p-6">{children}</main>
20
+ <main className="flex-1 overflow-y-auto p-4 md:p-6">{children}</main>
21
21
  </div>
22
22
  </div>
23
23
  );
@@ -52,67 +52,58 @@ export function useChat(ws: WsClient | null) {
52
52
  .catch(() => {});
53
53
  }, []);
54
54
 
55
- // Load messages when conversationId is set (with retry for worker restarts)
55
+ // Load messages when conversationId is set
56
56
  useEffect(() => {
57
57
  if (!conversationId) return;
58
- let cancelled = false;
59
- let retries = 0;
60
-
61
- const loadMessages = () => {
62
- fetch(`/api/conversations/${conversationId}`)
63
- .then((r) => {
64
- if (!r.ok) throw new Error('not found');
65
- return r.json();
66
- })
67
- .then((data) => {
68
- if (cancelled) return;
69
- if (data.messages?.length) {
70
- setMessages(
71
- data.messages
72
- .filter((m: any) => m.role === 'user' || m.role === 'assistant')
73
- .map((m: any) => {
74
- let audioData: string | undefined;
75
- if (m.audio_data) {
76
- if (m.audio_data.startsWith('data:')) {
77
- audioData = m.audio_data;
78
- } else if (m.audio_data.includes('/')) {
79
- audioData = `/api/files/${m.audio_data}`;
80
- } else {
81
- audioData = `data:audio/webm;base64,${m.audio_data}`;
82
- }
83
- }
84
-
85
- let attachments: StoredAttachment[] | undefined;
86
- if (m.attachments) {
87
- try {
88
- attachments = JSON.parse(m.attachments);
89
- } catch { /* ignore malformed */ }
58
+ fetch(`/api/conversations/${conversationId}`)
59
+ .then((r) => {
60
+ if (!r.ok) throw new Error('not found');
61
+ return r.json();
62
+ })
63
+ .then((data) => {
64
+ if (data.messages?.length) {
65
+ setMessages(
66
+ data.messages
67
+ .filter((m: any) => m.role === 'user' || m.role === 'assistant')
68
+ .map((m: any) => {
69
+ // Backward compat for audio_data: file path → URL, data: prefix → legacy, else → prepend data URL
70
+ let audioData: string | undefined;
71
+ if (m.audio_data) {
72
+ if (m.audio_data.startsWith('data:')) {
73
+ audioData = m.audio_data; // legacy data URL
74
+ } else if (m.audio_data.includes('/')) {
75
+ audioData = `/api/files/${m.audio_data}`; // file path → HTTP URL
76
+ } else {
77
+ audioData = `data:audio/webm;base64,${m.audio_data}`; // raw base64
90
78
  }
91
-
92
- return {
93
- id: m.id,
94
- role: m.role,
95
- content: m.content,
96
- timestamp: m.created_at,
97
- audioData,
98
- hasAttachments: !!(attachments && attachments.length > 0),
99
- attachments,
100
- };
101
- }),
102
- );
103
- }
104
- })
105
- .catch(() => {
106
- // Worker may be restarting — retry a few times
107
- if (!cancelled && retries < 5) {
108
- retries++;
109
- setTimeout(loadMessages, 1000);
110
- }
111
- });
112
- };
113
-
114
- loadMessages();
115
- return () => { cancelled = true; };
79
+ }
80
+
81
+ // Parse stored attachments
82
+ let attachments: StoredAttachment[] | undefined;
83
+ if (m.attachments) {
84
+ try {
85
+ attachments = JSON.parse(m.attachments);
86
+ } catch { /* ignore malformed */ }
87
+ }
88
+
89
+ return {
90
+ id: m.id,
91
+ role: m.role,
92
+ content: m.content,
93
+ timestamp: m.created_at,
94
+ audioData,
95
+ hasAttachments: !!(attachments && attachments.length > 0),
96
+ attachments,
97
+ };
98
+ }),
99
+ );
100
+ }
101
+ })
102
+ .catch(() => {
103
+ // Conversation gone clear
104
+ setConversationId(null);
105
+ fetch('/api/context/clear', { method: 'POST' }).catch(() => {});
106
+ });
116
107
  }, [conversationId]);
117
108
 
118
109
  // Persist conversationId to DB when it changes
@@ -132,8 +123,7 @@ export function useChat(ws: WsClient | null) {
132
123
  if (!ws) return;
133
124
 
134
125
  const unsubs = [
135
- ws.on('bot:typing', (data: { conversationId?: string }) => {
136
- if (data.conversationId) setConversationId(data.conversationId);
126
+ ws.on('bot:typing', () => {
137
127
  setStreaming(true);
138
128
  setTools([]);
139
129
  }),
@@ -233,14 +223,13 @@ export function useChat(ws: WsClient | null) {
233
223
  }, [ws, conversationId]);
234
224
 
235
225
  const clearContext = useCallback(() => {
236
- // Clear UI state only — starts a fresh conversation on next message.
237
- // Old messages stay in DB (used as context for the agent).
238
226
  setMessages([]);
239
227
  setConversationId(null);
240
228
  setStreamBuffer('');
241
229
  setStreaming(false);
242
230
  setTools([]);
243
231
  prevConvId.current = null;
232
+ loaded.current = false;
244
233
  fetch('/api/context/clear', { method: 'POST' }).catch(() => {});
245
234
  }, []);
246
235
 
@@ -20,7 +20,7 @@ export class WsClient {
20
20
 
21
21
  constructor(url?: string) {
22
22
  const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
23
- const host = location.host;
23
+ const host = import.meta.env.DEV ? 'localhost:3000' : location.host;
24
24
  this.url = url ?? `${proto}//${host}/ws`;
25
25
  }
26
26