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.
- package/bin/cli.js +57 -45
- package/cli/commands/daemon.ts +31 -0
- package/cli/commands/init.ts +24 -0
- package/cli/commands/start.ts +91 -0
- package/cli/commands/tunnel.ts +175 -0
- package/cli/commands/update.ts +141 -0
- package/cli/core/base-adapter.ts +99 -0
- package/cli/core/cloudflared.ts +71 -0
- package/cli/core/config.ts +58 -0
- package/cli/core/os-detector.ts +31 -0
- package/cli/core/server.ts +87 -0
- package/cli/core/types.ts +15 -0
- package/cli/index.ts +72 -0
- package/cli/platforms/darwin.ts +110 -0
- package/cli/platforms/index.ts +20 -0
- package/cli/platforms/linux.ts +116 -0
- package/cli/platforms/win32.ts +20 -0
- package/cli/utils/ui.ts +24 -0
- package/package.json +7 -3
- package/shared/paths.ts +1 -1
- package/supervisor/backend.ts +7 -6
- package/supervisor/fluxy-agent.ts +1 -1
- package/supervisor/index.ts +13 -3
- package/tsconfig.json +1 -1
- package/vite.config.ts +9 -2
|
@@ -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
|
+
}
|
package/cli/utils/ui.ts
ADDED
|
@@ -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.
|
|
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
|
|
package/supervisor/backend.ts
CHANGED
|
@@ -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(
|
|
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(
|
|
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:
|
|
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
|
-
|
|
68
|
-
|
|
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:
|
|
196
|
+
cwd: WORKSPACE_DIR,
|
|
197
197
|
permissionMode: 'bypassPermissions',
|
|
198
198
|
allowDangerouslySkipPermissions: true,
|
|
199
199
|
maxTurns: 50,
|
package/supervisor/index.ts
CHANGED
|
@@ -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 =
|
|
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:
|
|
7
|
+
root: process.env.FLUXY_WORKSPACE
|
|
8
|
+
? path.join(process.env.FLUXY_WORKSPACE, 'client')
|
|
9
|
+
: 'workspace/client',
|
|
8
10
|
resolve: {
|
|
9
|
-
alias: {
|
|
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',
|