fluxy-bot 0.9.0 → 0.9.2

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.
@@ -0,0 +1,20 @@
1
+ import pc from 'picocolors';
2
+
3
+ import { BaseAdapter } from '../core/base-adapter.js';
4
+ import type { DaemonConfig } from '../core/types.js';
5
+
6
+ export class WindowsAdapter extends BaseAdapter {
7
+ get hasDaemonSupport() { return false; }
8
+ get isInstalled() { return false; }
9
+ get isActive() { return false; }
10
+
11
+ protected installService(_config: DaemonConfig): void {
12
+ console.log(pc.yellow('Daemon mode is not supported on Windows natively yet. Use Task Scheduler.'));
13
+ }
14
+
15
+ protected startService(): void {}
16
+ protected stopService(): void {}
17
+ protected uninstallService(): void {}
18
+ protected showLogs(): void {}
19
+ protected checkStatus(): void {}
20
+ }
@@ -0,0 +1,24 @@
1
+ import pc from 'picocolors';
2
+ import { pkg } from '../core/config.js';
3
+
4
+ export function banner() {
5
+ const b1 = (s: string) => pc.bold(pc.blue(s));
6
+ const b2 = (s: string) => pc.bold(pc.magenta(s));
7
+ const dim = pc.dim;
8
+
9
+ console.log([
10
+ ``,
11
+ b1(` _______ _ `),
12
+ b1(` (_______) | `),
13
+ b1(` _____ | |_ _ _ _ _ _ `),
14
+ b1(` | ___) | | | | ( \\ / ) | | | `),
15
+ b2(` | | | | |_| |) X (| |_| | `),
16
+ b2(` |_| |_|\\____(_/ \\_)\\__ | `),
17
+ b2(` (____/ `),
18
+ dim(`v${pkg.version || '1.0.0'} · Self-hosted AI agent `),
19
+ ].join('\n'));
20
+ }
21
+
22
+ export function commandExample(name: string, cmd: string) {
23
+ return ` ${pc.dim(name)} ${pc.magenta(cmd)}`;
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "releaseNotes": [
5
5
  "Fixed some bugs to iOs ",
6
6
  "2. ",
@@ -15,6 +15,7 @@
15
15
  },
16
16
  "files": [
17
17
  "bin/",
18
+ "cli/",
18
19
  "dist-fluxy/",
19
20
  "supervisor/",
20
21
  "worker/",
@@ -50,6 +51,7 @@
50
51
  },
51
52
  "dependencies": {
52
53
  "@anthropic-ai/claude-agent-sdk": "^0.2.50",
54
+ "@clack/prompts": "^1.1.0",
53
55
  "@react-three/drei": "^10.7.7",
54
56
  "@react-three/fiber": "^9.5.0",
55
57
  "@tailwindcss/postcss": "^4.2.0",
@@ -58,12 +60,16 @@
58
60
  "better-sqlite3": "^12.6.2",
59
61
  "class-variance-authority": "^0.7.1",
60
62
  "clsx": "^2.1.1",
63
+ "commander": "^14.0.3",
61
64
  "cron-parser": "^5.5.0",
62
65
  "date-fns": "^4.1.0",
63
66
  "express": "^5.2.1",
64
67
  "framer-motion": "^12.34.3",
65
68
  "lucide-react": "^0.575.0",
69
+ "otpauth": "^9.3.6",
70
+ "picocolors": "^1.1.1",
66
71
  "postcss": "^8.5.6",
72
+ "qrcode": "^1.5.4",
67
73
  "radix-ui": "^1.4.3",
68
74
  "react": "^19.2.4",
69
75
  "react-dom": "^19.2.4",
@@ -78,8 +84,6 @@
78
84
  "tsx": "^4.21.0",
79
85
  "vite": "^7.3.1",
80
86
  "vite-plugin-pwa": "^1.2.0",
81
- "otpauth": "^9.3.6",
82
- "qrcode": "^1.5.4",
83
87
  "web-push": "^3.6.7",
84
88
  "ws": "^8.19.0",
85
89
  "zustand": "^5.0.11"
package/shared/paths.ts CHANGED
@@ -4,7 +4,7 @@ import { fileURLToPath } from 'url';
4
4
 
5
5
  export const PKG_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
6
6
  export const DATA_DIR = path.join(os.homedir(), '.fluxy');
7
- export const WORKSPACE_DIR = path.join(PKG_DIR, 'workspace');
7
+ export const WORKSPACE_DIR = process.env.FLUXY_WORKSPACE || path.join(PKG_DIR, 'workspace');
8
8
 
9
9
  const cfName = process.platform === 'win32' ? 'cloudflared.exe' : 'cloudflared';
10
10
 
@@ -1,7 +1,7 @@
1
1
  import { spawn, type ChildProcess } from 'child_process';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
- import { PKG_DIR } from '../shared/paths.js';
4
+ import { PKG_DIR, WORKSPACE_DIR } from '../shared/paths.js';
5
5
  import { log } from '../shared/logger.js';
6
6
 
7
7
  let child: ChildProcess | null = null;
@@ -11,14 +11,14 @@ let intentionallyStopped = false;
11
11
  const MAX_RESTARTS = 3;
12
12
  const STABLE_THRESHOLD = 30_000; // 30s — if backend ran this long, it wasn't a crash loop
13
13
 
14
- const LOG_FILE = path.join(PKG_DIR, 'workspace', '.backend.log');
14
+ const LOG_FILE = path.join(WORKSPACE_DIR, '.backend.log');
15
15
 
16
16
  export function getBackendPort(basePort: number): number {
17
17
  return basePort + 4;
18
18
  }
19
19
 
20
20
  export function spawnBackend(port: number): ChildProcess {
21
- const backendPath = path.join(PKG_DIR, 'workspace', 'backend', 'index.ts');
21
+ const backendPath = path.join(WORKSPACE_DIR, 'backend', 'index.ts');
22
22
  lastSpawnTime = Date.now();
23
23
  intentionallyStopped = false;
24
24
 
@@ -37,7 +37,7 @@ export function spawnBackend(port: number): ChildProcess {
37
37
  ].join('\n');
38
38
 
39
39
  child = spawn(process.execPath, ['--import', 'tsx/esm', '--input-type=module', '-e', wrapper], {
40
- cwd: path.join(PKG_DIR, 'workspace'),
40
+ cwd: WORKSPACE_DIR,
41
41
  stdio: ['ignore', 'pipe', 'pipe'],
42
42
  env: { ...process.env, BACKEND_PORT: String(port) },
43
43
  });
@@ -64,8 +64,9 @@ export function spawnBackend(port: number): ChildProcess {
64
64
  }
65
65
  if (restarts < MAX_RESTARTS) {
66
66
  restarts++;
67
- log.info(`Restarting backend (${restarts}/${MAX_RESTARTS})...`);
68
- setTimeout(() => spawnBackend(port), 1000 * restarts);
67
+ const delay = Math.min(1000 * restarts, 5000);
68
+ log.info(`Restarting backend (${restarts}/${MAX_RESTARTS}, delay ${delay}ms)...`);
69
+ setTimeout(() => spawnBackend(port), delay);
69
70
  } else {
70
71
  log.error('Backend failed too many times. Use Fluxy chat to debug.');
71
72
  }
@@ -193,7 +193,7 @@ export async function startFluxyAgentQuery(
193
193
  prompt: sdkPrompt,
194
194
  options: {
195
195
  model,
196
- cwd: path.join(PKG_DIR, 'workspace'),
196
+ cwd: WORKSPACE_DIR,
197
197
  permissionMode: 'bypassPermissions',
198
198
  allowDangerouslySkipPermissions: true,
199
199
  maxTurns: 50,
@@ -6,7 +6,7 @@ import { WebSocketServer, WebSocket } from 'ws';
6
6
  import { loadConfig, saveConfig } from '../shared/config.js';
7
7
  import { createProvider, type AiProvider, type ChatMessage } from '../shared/ai.js';
8
8
  import { paths } from '../shared/paths.js';
9
- import { PKG_DIR } from '../shared/paths.js';
9
+ import { PKG_DIR, DATA_DIR, WORKSPACE_DIR } from '../shared/paths.js';
10
10
  import { log } from '../shared/logger.js';
11
11
  import { startTunnel, stopTunnel, isTunnelAlive, restartTunnel, startNamedTunnel, restartNamedTunnel } from './tunnel.js';
12
12
  import { spawnWorker, stopWorker, getWorkerPort, isWorkerAlive } from './worker.js';
@@ -782,13 +782,23 @@ export async function startSupervisor() {
782
782
  // Run fluxy update in a detached process so it survives daemon stop/restart
783
783
  function runDeferredUpdate() {
784
784
  const cliPath = path.join(PKG_DIR, 'bin', 'cli.js');
785
+ const updateLog = path.join(DATA_DIR, 'update.log');
785
786
  log.info('Deferred update triggered — running fluxy update...');
786
787
  try {
788
+ const logFd = fs.openSync(updateLog, 'w');
787
789
  const child = cpSpawn(process.execPath, [cliPath, 'update'], {
788
790
  detached: true,
789
- stdio: 'ignore',
791
+ stdio: ['ignore', logFd, logFd],
790
792
  env: { ...process.env },
791
793
  });
794
+ child.on('exit', (code) => {
795
+ try { fs.closeSync(logFd); } catch {}
796
+ if (code === 0) {
797
+ log.ok('Update process completed successfully');
798
+ } else {
799
+ log.error(`Update process exited with code ${code} — see ${updateLog}`);
800
+ }
801
+ });
792
802
  child.unref();
793
803
  } catch (err) {
794
804
  log.error(`Deferred update failed: ${err instanceof Error ? err.message : err}`);
@@ -814,7 +824,7 @@ export async function startSupervisor() {
814
824
  // Watch workspace files for changes — auto-restart backend
815
825
  // Catches edits from VS Code, CLI, or any external tool.
816
826
  // During agent turns, defers to bot:done (avoids mid-turn restarts).
817
- const workspaceDir = path.join(PKG_DIR, 'workspace');
827
+ const workspaceDir = WORKSPACE_DIR;
818
828
  const backendDir = path.join(workspaceDir, 'backend');
819
829
  let backendRestartTimer: ReturnType<typeof setTimeout> | null = null;
820
830
 
package/tsconfig.json CHANGED
@@ -15,6 +15,6 @@
15
15
  "@client/*": ["./workspace/client/src/*"]
16
16
  }
17
17
  },
18
- "include": ["server/**/*", "workspace/client/src/**/*", "workspace/backend/**/*", "vite.config.ts"],
18
+ "include": ["server/**/*", "workspace/client/src/**/*", "workspace/backend/**/*", "cli/**/*", "vite.config.ts"],
19
19
  "exclude": ["node_modules", "dist", "data"]
20
20
  }
package/vite.config.ts CHANGED
@@ -4,9 +4,15 @@ import tailwindcss from '@tailwindcss/vite';
4
4
  import path from 'path';
5
5
 
6
6
  export default defineConfig({
7
- root: 'workspace/client',
7
+ root: process.env.FLUXY_WORKSPACE
8
+ ? path.join(process.env.FLUXY_WORKSPACE, 'client')
9
+ : 'workspace/client',
8
10
  resolve: {
9
- alias: { '@': path.resolve(__dirname, 'workspace/client/src') },
11
+ alias: {
12
+ '@': process.env.FLUXY_WORKSPACE
13
+ ? path.join(process.env.FLUXY_WORKSPACE, 'client/src')
14
+ : path.resolve(__dirname, 'workspace/client/src'),
15
+ },
10
16
  },
11
17
  build: {
12
18
  outDir: '../../dist',
@@ -45,6 +51,7 @@ export default defineConfig({
45
51
  'react',
46
52
  'react-dom/client',
47
53
  'react/jsx-runtime',
54
+ 'react-router',
48
55
  'lucide-react',
49
56
  'framer-motion',
50
57
  'recharts',