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/cli/index.ts DELETED
@@ -1,72 +0,0 @@
1
- import { Command } from 'commander';
2
- import { getAdapter } from './platforms/index.js';
3
- import { DATA_DIR } from './core/config.js';
4
- import os from 'node:os';
5
-
6
- import { registerDaemonCommand } from './commands/daemon.js';
7
- import { registerStartCommand } from './commands/start.js';
8
- import { registerTunnelCommand } from './commands/tunnel.js';
9
- import { registerUpdateCommand } from './commands/update.js';
10
- import { registerInitCommand } from './commands/init.js';
11
- import { pkg } from './core/config.js';
12
-
13
- const program = new Command();
14
-
15
- program
16
- .name('fluxy')
17
- .description('Fluxy Local AI and Tunneling Supervisor')
18
- .version(pkg.version);
19
-
20
- registerStartCommand(program);
21
- registerDaemonCommand(program);
22
- registerTunnelCommand(program);
23
- registerUpdateCommand(program);
24
- registerInitCommand(program);
25
-
26
- // Aliases for convenience matching the old CLI
27
- program
28
- .command('stop')
29
- .description('Stop the Fluxy daemon')
30
- .action(() => {
31
- getAdapter().handleDaemonAction('stop', {
32
- user: process.env.SUDO_USER || os.userInfo().username,
33
- home: process.env.FLUXY_REAL_HOME || os.homedir(),
34
- nodePath: process.env.FLUXY_NODE_PATH || process.execPath,
35
- dataDir: DATA_DIR
36
- });
37
- });
38
-
39
- program
40
- .command('status')
41
- .description('Check the Fluxy daemon status')
42
- .action(() => {
43
- getAdapter().handleDaemonAction('status', {
44
- user: process.env.SUDO_USER || os.userInfo().username,
45
- home: process.env.FLUXY_REAL_HOME || os.homedir(),
46
- nodePath: process.env.FLUXY_NODE_PATH || process.execPath,
47
- dataDir: DATA_DIR
48
- });
49
- });
50
-
51
- program
52
- .command('logs')
53
- .description('View the Fluxy daemon logs')
54
- .action(() => {
55
- getAdapter().handleDaemonAction('logs', {
56
- user: process.env.SUDO_USER || os.userInfo().username,
57
- home: process.env.FLUXY_REAL_HOME || os.homedir(),
58
- nodePath: process.env.FLUXY_NODE_PATH || process.execPath,
59
- dataDir: DATA_DIR
60
- });
61
- });
62
-
63
- if (process.argv.length === 2) {
64
- const fs = await import('node:fs');
65
- const { CONFIG_PATH } = await import('./core/config.js');
66
- if (fs.existsSync(CONFIG_PATH)) {
67
- process.argv.push('start');
68
- } else {
69
- process.argv.push('init');
70
- }
71
- }
72
- program.parse(process.argv);
@@ -1,146 +0,0 @@
1
- import { execSync, spawnSync } from 'node:child_process';
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
-
6
- import { BaseAdapter } from '../core/base-adapter.js';
7
- import type { DaemonConfig } from '../core/types.js';
8
-
9
- const LAUNCHD_LABEL = 'com.fluxy.bot';
10
-
11
- const LAUNCHD_PLIST_PATH = path.join(
12
- os.homedir(),
13
- 'Library',
14
- 'LaunchAgents',
15
- `${LAUNCHD_LABEL}.plist`
16
- );
17
-
18
- const LAUNCHD_LOG_DIR = path.join(os.homedir(), 'Library', 'Logs', 'fluxy');
19
-
20
- function generateLaunchdPlist({ nodePath, dataDir }: DaemonConfig) {
21
- const nodeBinDir = path.dirname(nodePath);
22
- fs.mkdirSync(LAUNCHD_LOG_DIR, { recursive: true });
23
- return `<?xml version="1.0" encoding="UTF-8"?>
24
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
25
- <plist version="1.0">
26
- <dict>
27
- <key>Label</key>
28
- <string>${LAUNCHD_LABEL}</string>
29
- <key>ProgramArguments</key>
30
- <array>
31
- <string>${nodePath}</string>
32
- <string>--import</string>
33
- <string>tsx/esm</string>
34
- <string>${dataDir}/supervisor/index.ts</string>
35
- </array>
36
- <key>WorkingDirectory</key>
37
- <string>${dataDir}</string>
38
- <key>EnvironmentVariables</key>
39
- <dict>
40
- <key>HOME</key>
41
- <string>${os.homedir()}</string>
42
- <key>NODE_ENV</key>
43
- <string>development</string>
44
- <key>NODE_PATH</key>
45
- <string>${dataDir}/node_modules</string>
46
- <key>PATH</key>
47
- <string>${nodeBinDir}:${dataDir}/node_modules/.bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
48
- </dict>
49
- <key>RunAtLoad</key>
50
- <true/>
51
- <key>KeepAlive</key>
52
- <dict>
53
- <key>SuccessfulExit</key>
54
- <false/>
55
- </dict>
56
- <key>ThrottleInterval</key>
57
- <integer>5</integer>
58
- <key>StandardOutPath</key>
59
- <string>${LAUNCHD_LOG_DIR}/fluxy.log</string>
60
- <key>StandardErrorPath</key>
61
- <string>${LAUNCHD_LOG_DIR}/fluxy.error.log</string>
62
- </dict>
63
- </plist>`;
64
- }
65
-
66
- export class DarwinAdapter extends BaseAdapter {
67
- get hasDaemonSupport() {
68
- return true;
69
- }
70
-
71
- get isInstalled() {
72
- return fs.existsSync(LAUNCHD_PLIST_PATH);
73
- }
74
-
75
- get isActive() {
76
- try {
77
- const out = execSync(
78
- `launchctl list ${LAUNCHD_LABEL} 2>/dev/null`,
79
- {
80
- encoding: 'utf-8'
81
- }
82
- );
83
-
84
- const pidLine = out.split('\n').find(l => l.includes('PID'));
85
- if (pidLine) {
86
- const pid = pidLine.split('=')[1]?.trim();
87
- return Boolean(pid && pid !== '0' && pid !== '-');
88
- }
89
-
90
- return !out.includes('"PID" = 0;');
91
- } catch {
92
- return false;
93
- }
94
- }
95
-
96
- protected installService(config: DaemonConfig): void {
97
- const plist = generateLaunchdPlist(config);
98
-
99
- fs.mkdirSync(path.dirname(LAUNCHD_PLIST_PATH), { recursive: true });
100
- fs.writeFileSync(LAUNCHD_PLIST_PATH, plist);
101
-
102
- execSync(`launchctl load "${LAUNCHD_PLIST_PATH}"`, {
103
- stdio: 'inherit'
104
- });
105
- }
106
-
107
- protected startService(): void {
108
- execSync(
109
- `launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null; launchctl load "${LAUNCHD_PLIST_PATH}"`,
110
- { stdio: 'inherit' }
111
- );
112
- }
113
-
114
- protected stopService(): void {
115
- execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}"`, {
116
- stdio: 'inherit'
117
- });
118
- }
119
-
120
- protected uninstallService(): void {
121
- try {
122
- execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, {
123
- stdio: 'ignore'
124
- });
125
- } catch {}
126
- if (fs.existsSync(LAUNCHD_PLIST_PATH)) {
127
- fs.unlinkSync(LAUNCHD_PLIST_PATH);
128
- }
129
- }
130
-
131
- protected showLogs(): void {
132
- const logPath = `${LAUNCHD_LOG_DIR}/fluxy.log`;
133
- if (fs.existsSync(logPath)) {
134
- spawnSync('tail', ['-f', logPath], { stdio: 'inherit' });
135
- } else {
136
- // oxlint-disable-next-line no-console
137
- console.log('Log file not found yet.');
138
- }
139
- }
140
-
141
- protected checkStatus(): void {
142
- try {
143
- execSync(`launchctl list ${LAUNCHD_LABEL}`, { stdio: 'inherit' });
144
- } catch {}
145
- }
146
- }
@@ -1,21 +0,0 @@
1
- import { getPlatform } from '../core/os-detector.js';
2
- import { BaseAdapter } from '../core/base-adapter.js';
3
-
4
- import { DarwinAdapter } from './darwin.js';
5
- import { LinuxAdapter } from './linux.js';
6
- import { WindowsAdapter } from './win32.js';
7
-
8
- export function getAdapter(): BaseAdapter {
9
- const platform = getPlatform();
10
-
11
- switch (platform) {
12
- case 'darwin':
13
- return new DarwinAdapter();
14
- case 'win32':
15
- return new WindowsAdapter();
16
- case 'linux':
17
- default:
18
- // Assuming fallback to linux for other unix-like
19
- return new LinuxAdapter();
20
- }
21
- }
@@ -1,156 +0,0 @@
1
- // oxlint-disable no-console
2
- import { execSync, spawnSync } from 'node:child_process';
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
-
7
- import pc from 'picocolors';
8
-
9
- import { BaseAdapter } from '../core/base-adapter.js';
10
- import { SERVICE_NAME } from '../core/config.js';
11
- import type { DaemonAction, DaemonConfig } from '../core/types.js';
12
-
13
- const SERVICE_PATH = `/etc/systemd/system/${SERVICE_NAME}.service`;
14
-
15
- function generateUnitFile({ user, home, nodePath, dataDir }: DaemonConfig) {
16
- const nodeBinDir = path.dirname(nodePath);
17
- return `[Unit]
18
- Description=Fluxy Bot
19
- After=network-online.target
20
- Wants=network-online.target
21
-
22
- [Service]
23
- Type=simple
24
- User=${user}
25
- WorkingDirectory=${dataDir}
26
- ExecStart=${nodePath} --import tsx/esm ${dataDir}/supervisor/index.ts
27
- Restart=on-failure
28
- RestartSec=5
29
- Environment=HOME=${home}
30
- Environment=NODE_ENV=development
31
- Environment=NODE_PATH=${dataDir}/node_modules
32
- Environment=PATH=${nodeBinDir}:${dataDir}/node_modules/.bin:/usr/local/bin:/usr/bin:/bin
33
- StandardOutput=journal
34
- StandardError=journal
35
- SyslogIdentifier=fluxy
36
-
37
- [Install]
38
- WantedBy=multi-user.target
39
- `;
40
- }
41
-
42
- export class LinuxAdapter extends BaseAdapter {
43
- get hasDaemonSupport(): boolean {
44
- try {
45
- execSync('systemctl --version', { stdio: 'ignore' });
46
- return true;
47
- } catch {
48
- return false;
49
- }
50
- }
51
-
52
- get isInstalled(): boolean {
53
- return fs.existsSync(SERVICE_PATH);
54
- }
55
-
56
- get isActive(): boolean {
57
- try {
58
- execSync(`systemctl is-active ${SERVICE_NAME}`, {
59
- stdio: 'ignore'
60
- });
61
- return true;
62
- } catch {
63
- return false;
64
- }
65
- }
66
-
67
- protected requiresPrivilegeEscalation(action: DaemonAction): boolean {
68
- if (action === 'status' || action === 'logs') return false;
69
- return process.getuid?.() !== 0;
70
- }
71
-
72
- protected escalatePrivileges(): void {
73
- const nodePath = process.env.FLUXY_NODE_PATH || process.execPath;
74
- const realHome = process.env.FLUXY_REAL_HOME || this.getRealHome();
75
- const args = process.argv.slice(1);
76
-
77
- console.log(pc.yellow('Sudo is required for this action.'));
78
- const result = spawnSync(
79
- 'sudo',
80
- [
81
- `FLUXY_NODE_PATH=${nodePath}`,
82
- `FLUXY_REAL_HOME=${realHome}`,
83
- nodePath,
84
- ...args
85
- ],
86
- { stdio: 'inherit' }
87
- );
88
- process.exit(result.status ?? 1);
89
- }
90
-
91
- private getRealUser() {
92
- return process.env.SUDO_USER || os.userInfo().username;
93
- }
94
-
95
- private getRealHome() {
96
- try {
97
- return execSync(`getent passwd ${this.getRealUser()}`, {
98
- encoding: 'utf-8'
99
- })
100
- .split(':')[5]
101
- .trim();
102
- } catch {
103
- return os.homedir();
104
- }
105
- }
106
-
107
- protected installService(config: DaemonConfig): void {
108
- const unit = generateUnitFile(config);
109
- fs.writeFileSync(SERVICE_PATH, unit);
110
-
111
- execSync(
112
- [
113
- `systemctl daemon-reload`,
114
- `systemctl enable ${SERVICE_NAME}`,
115
- `systemctl start ${SERVICE_NAME}`
116
- ].join('; '),
117
- { stdio: 'inherit' }
118
- );
119
- }
120
-
121
- protected startService(): void {
122
- execSync(`systemctl start ${SERVICE_NAME}`, { stdio: 'inherit' });
123
- }
124
-
125
- protected stopService(): void {
126
- execSync(`systemctl stop ${SERVICE_NAME}`, { stdio: 'inherit' });
127
- }
128
-
129
- protected uninstallService(): void {
130
- execSync(
131
- [
132
- `systemctl disable ${SERVICE_NAME}`,
133
- `systemctl stop ${SERVICE_NAME}`
134
- ].join('; '),
135
- { stdio: 'ignore' }
136
- );
137
- if (fs.existsSync(SERVICE_PATH)) {
138
- fs.unlinkSync(SERVICE_PATH);
139
- }
140
- execSync(`systemctl daemon-reload`, { stdio: 'ignore' });
141
- }
142
-
143
- protected showLogs(): void {
144
- spawnSync('journalctl', ['-u', SERVICE_NAME, '-f', '-n', '50'], {
145
- stdio: 'inherit'
146
- });
147
- }
148
-
149
- protected checkStatus(): void {
150
- try {
151
- execSync(`systemctl status ${SERVICE_NAME}`, { stdio: 'inherit' });
152
- } catch {
153
- // systemctl status returns non-zero when not active, ignoring
154
- }
155
- }
156
- }
@@ -1,34 +0,0 @@
1
- // oxlint-disable no-console
2
- // oxlint-disable no-unused-vars
3
- import pc from 'picocolors';
4
-
5
- import { BaseAdapter } from '../core/base-adapter.js';
6
- import type { DaemonConfig } from '../core/types.js';
7
-
8
- export class WindowsAdapter extends BaseAdapter {
9
- get hasDaemonSupport() {
10
- return false;
11
- }
12
-
13
- get isInstalled() {
14
- return false;
15
- }
16
-
17
- get isActive() {
18
- return false;
19
- }
20
-
21
- protected installService(config: DaemonConfig): void {
22
- console.log(
23
- pc.yellow(
24
- 'Daemon mode is not supported on Windows natively yet. Use Task Scheduler.'
25
- )
26
- );
27
- }
28
-
29
- protected startService(): void {}
30
- protected stopService(): void {}
31
- protected uninstallService(): void {}
32
- protected showLogs(): void {}
33
- protected checkStatus(): void {}
34
- }
package/cli/utils/ui.ts DELETED
@@ -1,37 +0,0 @@
1
- import pc from 'picocolors';
2
- import { pkg } from '../core/config.ts';
3
-
4
- export const logger = {
5
- info(...lines: (string | null | undefined)[]) {
6
- console.log(lines.filter(l => l != null).join('\n'));
7
- },
8
- warn(...lines: (string | null | undefined)[]) {
9
- console.warn(lines.filter(l => l != null).join('\n'));
10
- },
11
- error(...lines: (string | null | undefined)[]) {
12
- console.error(lines.filter(l => l != null).join('\n'));
13
- }
14
- };
15
-
16
- export function banner() {
17
- // A nice gradient-like or colorful output
18
- const b1 = (s: string) => pc.bold(pc.blue(s));
19
- const b2 = (s: string) => pc.bold(pc.magenta(s));
20
- const dim = pc.dim;
21
-
22
- logger.info(
23
- ``,
24
- b1(` _______ _ `),
25
- b1(` (_______) | `),
26
- b1(` _____ | |_ _ _ _ _ _ `),
27
- b1(` | ___) | | | | ( \\ / ) | | | `),
28
- b2(` | | | | |_| |) X (| |_| | `),
29
- b2(` |_| |_|\\____(_/ \\_)\\__ | `),
30
- b2(` (____/ `),
31
- dim(`v${pkg.version || '1.0.0'} · Self-hosted AI agent `)
32
- );
33
- }
34
-
35
- export function commandExample(name: string, cmd: string) {
36
- return ` ${pc.dim(name)} ${pc.magenta(cmd)}`;
37
- }