fluxy-bot 0.8.9 → 0.9.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.
Files changed (106) hide show
  1. package/README.md +53 -84
  2. package/bin/cli.js +1717 -6
  3. package/components.json +18 -18
  4. package/package.json +98 -109
  5. package/postcss.config.js +3 -3
  6. package/scripts/install.ps1 +1 -1
  7. package/scripts/install.sh +1 -1
  8. package/scripts/postinstall.js +47 -58
  9. package/shared/ai.ts +118 -202
  10. package/shared/config.ts +37 -39
  11. package/shared/logger.ts +6 -14
  12. package/shared/paths.ts +10 -16
  13. package/shared/relay.ts +89 -98
  14. package/supervisor/backend.ts +77 -89
  15. package/supervisor/chat/ARCHITECTURE.md +13 -14
  16. package/supervisor/chat/OnboardWizard.tsx +2194 -3419
  17. package/supervisor/chat/fluxy-main.tsx +495 -633
  18. package/supervisor/chat/fluxy.html +24 -36
  19. package/supervisor/chat/onboard-main.tsx +8 -8
  20. package/supervisor/chat/onboard.html +10 -13
  21. package/supervisor/chat/src/components/Chat/AudioBubble.tsx +94 -108
  22. package/supervisor/chat/src/components/Chat/ChatView.tsx +14 -36
  23. package/supervisor/chat/src/components/Chat/ImageLightbox.tsx +71 -89
  24. package/supervisor/chat/src/components/Chat/InputBar.tsx +498 -728
  25. package/supervisor/chat/src/components/Chat/MessageBubble.tsx +154 -246
  26. package/supervisor/chat/src/components/Chat/MessageList.tsx +114 -138
  27. package/supervisor/chat/src/components/Chat/TypingIndicator.tsx +38 -50
  28. package/supervisor/chat/src/components/LoginScreen.tsx +245 -296
  29. package/supervisor/chat/src/hooks/useChat.ts +210 -259
  30. package/supervisor/chat/src/hooks/useFluxyChat.ts +232 -322
  31. package/supervisor/chat/src/hooks/useSpeechRecognition.ts +126 -148
  32. package/supervisor/chat/src/lib/auth.ts +20 -23
  33. package/supervisor/chat/src/lib/ws-client.ts +113 -125
  34. package/supervisor/chat/src/styles/globals.css +76 -85
  35. package/supervisor/file-saver.ts +39 -52
  36. package/supervisor/fluxy-agent.ts +213 -292
  37. package/supervisor/index.ts +895 -1263
  38. package/supervisor/scheduler.ts +237 -299
  39. package/supervisor/tunnel.ts +113 -167
  40. package/supervisor/vite-dev.ts +51 -61
  41. package/supervisor/widget.js +135 -147
  42. package/supervisor/worker.ts +45 -49
  43. package/tsconfig.json +18 -24
  44. package/vite.config.ts +48 -55
  45. package/vite.fluxy.config.ts +34 -34
  46. package/worker/claude-auth.ts +202 -265
  47. package/worker/codex-auth.ts +144 -181
  48. package/worker/db.ts +63 -191
  49. package/worker/index.ts +601 -842
  50. package/workspace/MYSELF.md +1 -1
  51. package/workspace/PULSE.json +6 -6
  52. package/workspace/backend/index.ts +16 -19
  53. package/workspace/client/index.html +47 -60
  54. package/workspace/client/public/manifest.json +21 -21
  55. package/workspace/client/public/sw.js +29 -31
  56. package/workspace/client/src/App.tsx +91 -136
  57. package/workspace/client/src/components/Dashboard/DashboardPage.tsx +68 -72
  58. package/workspace/client/src/components/ErrorBoundary.tsx +11 -11
  59. package/workspace/client/src/components/Layout/DashboardLayout.tsx +35 -35
  60. package/workspace/client/src/components/Layout/Footer.tsx +12 -12
  61. package/workspace/client/src/components/Layout/MobileNav.tsx +23 -23
  62. package/workspace/client/src/components/Layout/Sidebar.tsx +81 -81
  63. package/workspace/client/src/components/ui/avatar.tsx +85 -85
  64. package/workspace/client/src/components/ui/badge.tsx +40 -41
  65. package/workspace/client/src/components/ui/button.tsx +56 -57
  66. package/workspace/client/src/components/ui/card.tsx +75 -75
  67. package/workspace/client/src/components/ui/dialog.tsx +114 -117
  68. package/workspace/client/src/components/ui/dropdown-menu.tsx +191 -199
  69. package/workspace/client/src/components/ui/input.tsx +17 -17
  70. package/workspace/client/src/components/ui/scroll-area.tsx +47 -47
  71. package/workspace/client/src/components/ui/select.tsx +145 -151
  72. package/workspace/client/src/components/ui/separator.tsx +21 -21
  73. package/workspace/client/src/components/ui/sheet.tsx +102 -102
  74. package/workspace/client/src/components/ui/skeleton.tsx +10 -10
  75. package/workspace/client/src/components/ui/switch.tsx +26 -26
  76. package/workspace/client/src/components/ui/tabs.tsx +69 -69
  77. package/workspace/client/src/components/ui/textarea.tsx +14 -14
  78. package/workspace/client/src/components/ui/tooltip.tsx +37 -37
  79. package/workspace/client/src/lib/utils.ts +1 -1
  80. package/workspace/client/src/main.tsx +3 -3
  81. package/workspace/client/src/styles/globals.css +76 -85
  82. package/workspace/skills/code-reviewer/.claude-plugin/plugin.json +3 -3
  83. package/workspace/skills/code-reviewer/skills/code-reviewer/SKILL.md +0 -6
  84. package/workspace/skills/daily-standup/.claude-plugin/plugin.json +3 -3
  85. package/workspace/skills/daily-standup/skills/daily-standup/SKILL.md +0 -7
  86. package/workspace/skills/workspace-helper/.claude-plugin/plugin.json +3 -3
  87. package/workspace/skills/workspace-helper/skills/workspace-helper/SKILL.md +0 -2
  88. package/bin/cli.backup.js +0 -2138
  89. package/cli/commands/daemon.ts +0 -42
  90. package/cli/commands/init.ts +0 -32
  91. package/cli/commands/start.ts +0 -113
  92. package/cli/commands/tunnel.temp.ts +0 -206
  93. package/cli/commands/tunnel.ts +0 -227
  94. package/cli/commands/update.ts +0 -163
  95. package/cli/core/base-adapter.ts +0 -156
  96. package/cli/core/cloudflared.ts +0 -113
  97. package/cli/core/config.ts +0 -73
  98. package/cli/core/os-detector.ts +0 -43
  99. package/cli/core/server.ts +0 -109
  100. package/cli/core/types.ts +0 -15
  101. package/cli/index.ts +0 -72
  102. package/cli/platforms/darwin.ts +0 -146
  103. package/cli/platforms/index.ts +0 -21
  104. package/cli/platforms/linux.ts +0 -156
  105. package/cli/platforms/win32.ts +0 -34
  106. package/cli/utils/ui.ts +0 -37
package/shared/ai.ts CHANGED
@@ -1,225 +1,141 @@
1
1
  export interface ChatMessage {
2
- role: 'user' | 'assistant' | 'system';
3
- content: string;
2
+ role: 'user' | 'assistant' | 'system';
3
+ content: string;
4
4
  }
5
5
 
6
6
  export interface AiProvider {
7
- name: string;
8
- chat(
9
- messages: ChatMessage[],
10
- model: string,
11
- onToken: (token: string) => void,
12
- onDone: (
13
- full: string,
14
- usage?: { tokensIn: number; tokensOut: number }
15
- ) => void,
16
- onError: (err: Error) => void,
17
- signal?: AbortSignal
18
- ): void;
7
+ name: string;
8
+ chat(
9
+ messages: ChatMessage[],
10
+ model: string,
11
+ onToken: (token: string) => void,
12
+ onDone: (full: string, usage?: { tokensIn: number; tokensOut: number }) => void,
13
+ onError: (err: Error) => void,
14
+ signal?: AbortSignal,
15
+ ): void;
19
16
  }
20
17
 
21
- export function createProvider(
22
- provider: string,
23
- apiKey: string,
24
- baseUrl?: string
25
- ): AiProvider | null {
26
- switch (provider) {
27
- case 'openai':
28
- return openai(apiKey, baseUrl);
29
- case 'anthropic':
30
- return anthropic(apiKey);
31
- case 'ollama':
32
- return ollama(baseUrl);
33
- default:
34
- return null;
35
- }
18
+ export function createProvider(provider: string, apiKey: string, baseUrl?: string): AiProvider | null {
19
+ switch (provider) {
20
+ case 'openai': return openai(apiKey, baseUrl);
21
+ case 'anthropic': return anthropic(apiKey);
22
+ case 'ollama': return ollama(baseUrl);
23
+ default: return null;
24
+ }
36
25
  }
37
26
 
38
27
  // ── SSE line parser ──
39
28
 
40
- async function readSSE(
41
- res: Response,
42
- onLine: (line: string) => void,
43
- signal?: AbortSignal
44
- ) {
45
- const reader = res.body!.getReader();
46
- const dec = new TextDecoder();
47
- let buf = '';
48
- while (true) {
49
- if (signal?.aborted) break;
50
- const { done, value } = await reader.read();
51
- if (done) break;
52
- buf += dec.decode(value, { stream: true });
53
- const lines = buf.split('\n');
54
- buf = lines.pop()!;
55
- for (const line of lines) {
56
- if (line.startsWith('data: ') && line !== 'data: [DONE]')
57
- onLine(line.slice(6));
58
- }
29
+ async function readSSE(res: Response, onLine: (line: string) => void, signal?: AbortSignal) {
30
+ const reader = res.body!.getReader();
31
+ const dec = new TextDecoder();
32
+ let buf = '';
33
+ while (true) {
34
+ if (signal?.aborted) break;
35
+ const { done, value } = await reader.read();
36
+ if (done) break;
37
+ buf += dec.decode(value, { stream: true });
38
+ const lines = buf.split('\n');
39
+ buf = lines.pop()!;
40
+ for (const line of lines) {
41
+ if (line.startsWith('data: ') && line !== 'data: [DONE]') onLine(line.slice(6));
59
42
  }
43
+ }
60
44
  }
61
45
 
62
46
  // ── Providers (raw fetch, zero deps) ──
63
47
 
64
- function openai(
65
- apiKey: string,
66
- baseUrl = 'https://api.openai.com/v1'
67
- ): AiProvider {
68
- return {
69
- name: 'openai',
70
- async chat(messages, model, onToken, onDone, onError, signal) {
71
- try {
72
- const res = await fetch(`${baseUrl}/chat/completions`, {
73
- method: 'POST',
74
- headers: {
75
- Authorization: `Bearer ${apiKey}`,
76
- 'Content-Type': 'application/json'
77
- },
78
- body: JSON.stringify({
79
- model,
80
- messages,
81
- stream: true,
82
- stream_options: { include_usage: true }
83
- }),
84
- signal
85
- });
86
- if (!res.ok)
87
- throw new Error(
88
- `OpenAI ${res.status}: ${await res.text()}`
89
- );
90
- let full = '';
91
- let usage: { tokensIn: number; tokensOut: number } | undefined;
92
- await readSSE(
93
- res,
94
- line => {
95
- const j = JSON.parse(line);
96
- const t = j.choices?.[0]?.delta?.content;
97
- if (t) {
98
- full += t;
99
- onToken(t);
100
- }
101
- if (j.usage)
102
- usage = {
103
- tokensIn: j.usage.prompt_tokens,
104
- tokensOut: j.usage.completion_tokens
105
- };
106
- },
107
- signal
108
- );
109
- onDone(full, usage);
110
- } catch (e) {
111
- if (!signal?.aborted)
112
- onError(e instanceof Error ? e : new Error(String(e)));
113
- }
114
- }
115
- };
48
+ function openai(apiKey: string, baseUrl = 'https://api.openai.com/v1'): AiProvider {
49
+ return {
50
+ name: 'openai',
51
+ async chat(messages, model, onToken, onDone, onError, signal) {
52
+ try {
53
+ const res = await fetch(`${baseUrl}/chat/completions`, {
54
+ method: 'POST',
55
+ headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
56
+ body: JSON.stringify({ model, messages, stream: true, stream_options: { include_usage: true } }),
57
+ signal,
58
+ });
59
+ if (!res.ok) throw new Error(`OpenAI ${res.status}: ${await res.text()}`);
60
+ let full = '';
61
+ let usage: { tokensIn: number; tokensOut: number } | undefined;
62
+ await readSSE(res, (line) => {
63
+ const j = JSON.parse(line);
64
+ const t = j.choices?.[0]?.delta?.content;
65
+ if (t) { full += t; onToken(t); }
66
+ if (j.usage) usage = { tokensIn: j.usage.prompt_tokens, tokensOut: j.usage.completion_tokens };
67
+ }, signal);
68
+ onDone(full, usage);
69
+ } catch (e) { if (!signal?.aborted) onError(e instanceof Error ? e : new Error(String(e))); }
70
+ },
71
+ };
116
72
  }
117
73
 
118
74
  function anthropic(apiKey: string): AiProvider {
119
- return {
120
- name: 'anthropic',
121
- async chat(messages, model, onToken, onDone, onError, signal) {
122
- try {
123
- const sys = messages.find(m => m.role === 'system');
124
- const msgs = messages.filter(m => m.role !== 'system');
125
- const res = await fetch(
126
- 'https://api.anthropic.com/v1/messages',
127
- {
128
- method: 'POST',
129
- headers: {
130
- 'x-api-key': apiKey,
131
- 'anthropic-version': '2023-06-01',
132
- 'Content-Type': 'application/json'
133
- },
134
- body: JSON.stringify({
135
- model,
136
- max_tokens: 4096,
137
- system: sys?.content,
138
- messages: msgs,
139
- stream: true
140
- }),
141
- signal
142
- }
143
- );
144
- if (!res.ok)
145
- throw new Error(
146
- `Anthropic ${res.status}: ${await res.text()}`
147
- );
148
- let full = '';
149
- let usage: { tokensIn: number; tokensOut: number } | undefined;
150
- await readSSE(
151
- res,
152
- line => {
153
- const j = JSON.parse(line);
154
- if (j.type === 'content_block_delta' && j.delta?.text) {
155
- full += j.delta.text;
156
- onToken(j.delta.text);
157
- }
158
- if (j.type === 'message_delta' && j.usage) {
159
- usage = {
160
- tokensIn: j.usage?.input_tokens ?? 0,
161
- tokensOut: j.usage.output_tokens
162
- };
163
- }
164
- if (j.type === 'message_start' && j.message?.usage) {
165
- usage = {
166
- tokensIn: j.message.usage.input_tokens,
167
- tokensOut: 0
168
- };
169
- }
170
- },
171
- signal
172
- );
173
- onDone(full, usage);
174
- } catch (e) {
175
- if (!signal?.aborted)
176
- onError(e instanceof Error ? e : new Error(String(e)));
177
- }
178
- }
179
- };
75
+ return {
76
+ name: 'anthropic',
77
+ async chat(messages, model, onToken, onDone, onError, signal) {
78
+ try {
79
+ const sys = messages.find((m) => m.role === 'system');
80
+ const msgs = messages.filter((m) => m.role !== 'system');
81
+ const res = await fetch('https://api.anthropic.com/v1/messages', {
82
+ method: 'POST',
83
+ headers: {
84
+ 'x-api-key': apiKey,
85
+ 'anthropic-version': '2023-06-01',
86
+ 'Content-Type': 'application/json',
87
+ },
88
+ body: JSON.stringify({ model, max_tokens: 4096, system: sys?.content, messages: msgs, stream: true }),
89
+ signal,
90
+ });
91
+ if (!res.ok) throw new Error(`Anthropic ${res.status}: ${await res.text()}`);
92
+ let full = '';
93
+ let usage: { tokensIn: number; tokensOut: number } | undefined;
94
+ await readSSE(res, (line) => {
95
+ const j = JSON.parse(line);
96
+ if (j.type === 'content_block_delta' && j.delta?.text) {
97
+ full += j.delta.text;
98
+ onToken(j.delta.text);
99
+ }
100
+ if (j.type === 'message_delta' && j.usage) {
101
+ usage = { tokensIn: j.usage?.input_tokens ?? 0, tokensOut: j.usage.output_tokens };
102
+ }
103
+ if (j.type === 'message_start' && j.message?.usage) {
104
+ usage = { tokensIn: j.message.usage.input_tokens, tokensOut: 0 };
105
+ }
106
+ }, signal);
107
+ onDone(full, usage);
108
+ } catch (e) { if (!signal?.aborted) onError(e instanceof Error ? e : new Error(String(e))); }
109
+ },
110
+ };
180
111
  }
181
112
 
182
113
  function ollama(baseUrl = 'http://localhost:11434'): AiProvider {
183
- return {
184
- name: 'ollama',
185
- async chat(messages, model, onToken, onDone, onError, signal) {
186
- try {
187
- const res = await fetch(`${baseUrl}/api/chat`, {
188
- method: 'POST',
189
- headers: { 'Content-Type': 'application/json' },
190
- body: JSON.stringify({ model, messages, stream: true }),
191
- signal
192
- });
193
- if (!res.ok) throw new Error(`Ollama ${res.status}`);
194
- const reader = res.body!.getReader();
195
- const dec = new TextDecoder();
196
- let full = '';
197
- while (true) {
198
- const { done, value } = await reader.read();
199
- if (done) break;
200
- for (const line of dec
201
- .decode(value, { stream: true })
202
- .split('\n')
203
- .filter(Boolean)) {
204
- const j = JSON.parse(line);
205
- if (j.message?.content) {
206
- full += j.message.content;
207
- onToken(j.message.content);
208
- }
209
- if (j.done) {
210
- onDone(full, {
211
- tokensIn: j.prompt_eval_count ?? 0,
212
- tokensOut: j.eval_count ?? 0
213
- });
214
- return;
215
- }
216
- }
217
- }
218
- onDone(full);
219
- } catch (e) {
220
- if (!signal?.aborted)
221
- onError(e instanceof Error ? e : new Error(String(e)));
222
- }
114
+ return {
115
+ name: 'ollama',
116
+ async chat(messages, model, onToken, onDone, onError, signal) {
117
+ try {
118
+ const res = await fetch(`${baseUrl}/api/chat`, {
119
+ method: 'POST',
120
+ headers: { 'Content-Type': 'application/json' },
121
+ body: JSON.stringify({ model, messages, stream: true }),
122
+ signal,
123
+ });
124
+ if (!res.ok) throw new Error(`Ollama ${res.status}`);
125
+ const reader = res.body!.getReader();
126
+ const dec = new TextDecoder();
127
+ let full = '';
128
+ while (true) {
129
+ const { done, value } = await reader.read();
130
+ if (done) break;
131
+ for (const line of dec.decode(value, { stream: true }).split('\n').filter(Boolean)) {
132
+ const j = JSON.parse(line);
133
+ if (j.message?.content) { full += j.message.content; onToken(j.message.content); }
134
+ if (j.done) { onDone(full, { tokensIn: j.prompt_eval_count ?? 0, tokensOut: j.eval_count ?? 0 }); return; }
135
+ }
223
136
  }
224
- };
137
+ onDone(full);
138
+ } catch (e) { if (!signal?.aborted) onError(e instanceof Error ? e : new Error(String(e))); }
139
+ },
140
+ };
225
141
  }
package/shared/config.ts CHANGED
@@ -2,52 +2,50 @@ import fs from 'fs';
2
2
  import { paths, DATA_DIR } from './paths.js';
3
3
 
4
4
  export interface BotConfig {
5
- port: number;
6
- username: string;
7
- ai: {
8
- provider: 'openai' | 'anthropic' | 'ollama' | '';
9
- model: string;
10
- apiKey: string;
11
- baseUrl?: string;
12
- };
13
- tunnel: {
14
- mode: 'off' | 'quick' | 'named';
15
- name?: string;
16
- domain?: string;
17
- configPath?: string;
18
- enabled?: boolean; // for backward compatibility
19
- };
20
- relay: {
21
- token: string;
22
- tier: string;
23
- url: string;
24
- };
25
- tunnelUrl?: string;
5
+ port: number;
6
+ username: string;
7
+ ai: {
8
+ provider: 'openai' | 'anthropic' | 'ollama' | '';
9
+ model: string;
10
+ apiKey: string;
11
+ baseUrl?: string;
12
+ };
13
+ tunnel: {
14
+ mode: 'off' | 'quick' | 'named';
15
+ name?: string;
16
+ domain?: string;
17
+ configPath?: string;
18
+ };
19
+ relay: {
20
+ token: string;
21
+ tier: string;
22
+ url: string;
23
+ };
24
+ tunnelUrl?: string;
26
25
  }
27
26
 
28
- export const DEFAULTS: BotConfig = {
29
- port: 3000,
30
- username: '',
31
- ai: { provider: '', model: '', apiKey: '' },
32
- tunnel: { mode: 'quick' },
33
- relay: { token: '', tier: '', url: '' }
27
+ const DEFAULTS: BotConfig = {
28
+ port: 3000,
29
+ username: '',
30
+ ai: { provider: '', model: '', apiKey: '' },
31
+ tunnel: { mode: 'quick' },
32
+ relay: { token: '', tier: '', url: '' },
34
33
  };
35
34
 
36
35
  export function loadConfig(): BotConfig {
37
- if (!fs.existsSync(paths.config))
38
- throw new Error('No config. Run `fluxy init`.');
39
- const config = JSON.parse(fs.readFileSync(paths.config, 'utf-8'));
36
+ if (!fs.existsSync(paths.config)) throw new Error('No config. Run `fluxy init`.');
37
+ const config = JSON.parse(fs.readFileSync(paths.config, 'utf-8'));
40
38
 
41
- // Backward compat: migrate old { enabled: boolean } → { mode }
42
- if ('enabled' in config.tunnel && !('mode' in config.tunnel)) {
43
- config.tunnel = { mode: config.tunnel.enabled ? 'quick' : 'off' };
44
- saveConfig(config);
45
- }
39
+ // Backward compat: migrate old { enabled: boolean } → { mode }
40
+ if ('enabled' in config.tunnel && !('mode' in config.tunnel)) {
41
+ config.tunnel = { mode: config.tunnel.enabled ? 'quick' : 'off' };
42
+ saveConfig(config);
43
+ }
46
44
 
47
- return config;
45
+ return config;
48
46
  }
49
47
 
50
48
  export function saveConfig(config: BotConfig): void {
51
- fs.mkdirSync(DATA_DIR, { recursive: true });
52
- fs.writeFileSync(paths.config, JSON.stringify(config, null, 2));
53
- }
49
+ fs.mkdirSync(DATA_DIR, { recursive: true });
50
+ fs.writeFileSync(paths.config, JSON.stringify(config, null, 2));
51
+ }
package/shared/logger.ts CHANGED
@@ -1,21 +1,13 @@
1
1
  const c = {
2
- r: '\x1b[0m',
3
- d: '\x1b[2m',
4
- g: '\x1b[32m',
5
- y: '\x1b[33m',
6
- red: '\x1b[31m',
7
- cy: '\x1b[36m'
2
+ r: '\x1b[0m', d: '\x1b[2m',
3
+ g: '\x1b[32m', y: '\x1b[33m', red: '\x1b[31m', cy: '\x1b[36m',
8
4
  };
9
5
 
10
6
  const ts = () => new Date().toLocaleTimeString('en-GB', { hour12: false });
11
7
 
12
8
  export const log = {
13
- info: (msg: string, ...a: unknown[]) =>
14
- console.log(`${c.d}${ts()}${c.r} ${c.cy}INFO${c.r} ${msg}`, ...a),
15
- warn: (msg: string, ...a: unknown[]) =>
16
- console.warn(`${c.d}${ts()}${c.r} ${c.y}WARN${c.r} ${msg}`, ...a),
17
- error: (msg: string, ...a: unknown[]) =>
18
- console.error(`${c.d}${ts()}${c.r} ${c.red}ERR${c.r} ${msg}`, ...a),
19
- ok: (msg: string, ...a: unknown[]) =>
20
- console.log(`${c.d}${ts()}${c.r} ${c.g}OK${c.r} ${msg}`, ...a)
9
+ info: (msg: string, ...a: unknown[]) => console.log(`${c.d}${ts()}${c.r} ${c.cy}INFO${c.r} ${msg}`, ...a),
10
+ warn: (msg: string, ...a: unknown[]) => console.warn(`${c.d}${ts()}${c.r} ${c.y}WARN${c.r} ${msg}`, ...a),
11
+ error: (msg: string, ...a: unknown[]) => console.error(`${c.d}${ts()}${c.r} ${c.red}ERR${c.r} ${msg}`, ...a),
12
+ ok: (msg: string, ...a: unknown[]) => console.log(`${c.d}${ts()}${c.r} ${c.g}OK${c.r} ${msg}`, ...a),
21
13
  };
package/shared/paths.ts CHANGED
@@ -2,25 +2,19 @@ import path from 'path';
2
2
  import os from 'os';
3
3
  import { fileURLToPath } from 'url';
4
4
 
5
- export const PKG_DIR = path.resolve(
6
- path.dirname(fileURLToPath(import.meta.url)),
7
- '..'
8
- );
5
+ export const PKG_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
9
6
  export const DATA_DIR = path.join(os.homedir(), '.fluxy');
10
- export const WORKSPACE_DIR =
11
- process.env.FLUXY_WORKSPACE || path.join(PKG_DIR, 'workspace');
12
-
13
- console.log('Using workspace directory:', WORKSPACE_DIR);
7
+ export const WORKSPACE_DIR = path.join(PKG_DIR, 'workspace');
14
8
 
15
9
  const cfName = process.platform === 'win32' ? 'cloudflared.exe' : 'cloudflared';
16
10
 
17
11
  export const paths = {
18
- config: path.join(DATA_DIR, 'config.json'),
19
- db: path.join(DATA_DIR, 'memory.db'),
20
- widgetJs: path.join(PKG_DIR, 'supervisor', 'widget.js'),
21
- cloudflared: path.join(DATA_DIR, 'bin', cfName),
22
- files: path.join(WORKSPACE_DIR, 'files'),
23
- filesAudio: path.join(WORKSPACE_DIR, 'files', 'audio'),
24
- filesImages: path.join(WORKSPACE_DIR, 'files', 'images'),
25
- filesDocuments: path.join(WORKSPACE_DIR, 'files', 'documents')
12
+ config: path.join(DATA_DIR, 'config.json'),
13
+ db: path.join(DATA_DIR, 'memory.db'),
14
+ widgetJs: path.join(PKG_DIR, 'supervisor', 'widget.js'),
15
+ cloudflared: path.join(DATA_DIR, 'bin', cfName),
16
+ files: path.join(WORKSPACE_DIR, 'files'),
17
+ filesAudio: path.join(WORKSPACE_DIR, 'files', 'audio'),
18
+ filesImages: path.join(WORKSPACE_DIR, 'files', 'images'),
19
+ filesDocuments: path.join(WORKSPACE_DIR, 'files', 'documents'),
26
20
  };