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
@@ -1,163 +0,0 @@
1
- import { Command } from 'commander';
2
- import { spinner, intro, outro } from '@clack/prompts';
3
- import pc from 'picocolors';
4
- import fs from 'node:fs';
5
- import path from 'node:path';
6
- import os from 'node:os';
7
- import { execSync } from 'node:child_process';
8
- import { pkg, DATA_DIR } from '../core/config.js';
9
- import { getAdapter } from '../platforms/index.js';
10
-
11
- export function registerUpdateCommand(program: Command) {
12
- program
13
- .command('update')
14
- .description('Update Fluxy to the latest version')
15
- .action(async () => {
16
- intro(pc.inverse(' Fluxy Update '));
17
- const currentVersion = pkg.version;
18
- console.log(pc.dim(`Current version: v${currentVersion}`));
19
-
20
- const s = spinner();
21
- s.start('Checking for updates...');
22
-
23
- let latest;
24
- try {
25
- const res = await fetch(
26
- 'https://registry.npmjs.org/fluxy-bot/latest'
27
- );
28
- if (!res.ok) throw new Error('Refresh failed');
29
- latest = await res.json();
30
- } catch (e: any) {
31
- s.stop(pc.red('Failed to check for updates. ' + e.message));
32
- process.exit(1);
33
- }
34
-
35
- if (currentVersion === latest.version) {
36
- s.stop(pc.green(`Already up to date (v${currentVersion})`));
37
- outro('Nothing to do!');
38
- return;
39
- }
40
-
41
- s.message(`Found v${latest.version}. Downloading...`);
42
-
43
- const adapter = getAdapter();
44
- const daemonWasRunning =
45
- fs.existsSync(DATA_DIR) && adapter.isInstalled; // simplified check
46
-
47
- if (daemonWasRunning && adapter.isActive) {
48
- s.message('Stopping daemon...');
49
- try {
50
- adapter.handleDaemonAction('stop', {
51
- user: os.userInfo().username,
52
- home: os.homedir(),
53
- nodePath: process.execPath,
54
- dataDir: DATA_DIR
55
- });
56
- } catch {}
57
- }
58
-
59
- const tmpDir = path.join(os.tmpdir(), `fluxy-update-${Date.now()}`);
60
- fs.mkdirSync(tmpDir, { recursive: true });
61
- const tarballFilePath = path.join(tmpDir, 'fluxy.tgz');
62
-
63
- try {
64
- const res = await fetch(latest.dist.tarball);
65
- if (!res.ok) throw new Error('Download failed');
66
- const buf = Buffer.from(await res.arrayBuffer());
67
- fs.writeFileSync(tarballFilePath, buf);
68
- execSync(`tar xzf "${tarballFilePath}" -C "${tmpDir}"`, {
69
- stdio: 'ignore'
70
- });
71
- } catch (e: any) {
72
- s.stop(pc.red('Download failed: ' + e.message));
73
- fs.rmSync(tmpDir, { recursive: true, force: true });
74
- process.exit(1);
75
- }
76
-
77
- s.message('Updating files...');
78
- const extracted = path.join(tmpDir, 'package');
79
-
80
- for (const dir of [
81
- 'bin',
82
- 'supervisor',
83
- 'worker',
84
- 'shared',
85
- 'scripts'
86
- ]) {
87
- const src = path.join(extracted, dir);
88
- if (fs.existsSync(src)) {
89
- fs.cpSync(src, path.join(DATA_DIR, dir), {
90
- recursive: true,
91
- force: true
92
- });
93
- }
94
- }
95
-
96
- const wsSrc = path.join(extracted, 'workspace');
97
- if (
98
- !fs.existsSync(path.join(DATA_DIR, 'workspace')) &&
99
- fs.existsSync(wsSrc)
100
- ) {
101
- fs.cpSync(wsSrc, path.join(DATA_DIR, 'workspace'), {
102
- recursive: true
103
- });
104
- }
105
-
106
- for (const file of [
107
- 'package.json',
108
- 'vite.config.ts',
109
- 'vite.fluxy.config.ts',
110
- 'tsconfig.json',
111
- 'postcss.config.js',
112
- 'components.json'
113
- ]) {
114
- const src = path.join(extracted, file);
115
- if (fs.existsSync(src)) {
116
- fs.cpSync(src, path.join(DATA_DIR, file), { force: true });
117
- }
118
- }
119
-
120
- const distSrc = path.join(extracted, 'dist-fluxy');
121
- const distDst = path.join(DATA_DIR, 'dist-fluxy');
122
- if (fs.existsSync(distSrc)) {
123
- fs.rmSync(distDst, { recursive: true, force: true });
124
- fs.cpSync(distSrc, distDst, { recursive: true });
125
- }
126
-
127
- s.message('Installing dependencies...');
128
- try {
129
- execSync('npm install --omit=dev', {
130
- cwd: DATA_DIR,
131
- stdio: 'ignore'
132
- });
133
- } catch {}
134
-
135
- if (!fs.existsSync(path.join(distDst, 'onboard.html'))) {
136
- s.message('Building interface...');
137
- try {
138
- execSync('npm run build:fluxy', {
139
- cwd: DATA_DIR,
140
- stdio: 'ignore'
141
- });
142
- } catch {}
143
- }
144
-
145
- fs.writeFileSync(path.join(DATA_DIR, '.version'), latest.version);
146
- fs.rmSync(tmpDir, { recursive: true, force: true });
147
-
148
- if (daemonWasRunning) {
149
- s.message('Restarting daemon...');
150
- try {
151
- adapter.handleDaemonAction('start', {
152
- user: os.userInfo().username,
153
- home: os.homedir(),
154
- nodePath: process.execPath,
155
- dataDir: DATA_DIR
156
- });
157
- } catch {}
158
- }
159
-
160
- s.stop(pc.green(`Successfully updated to v${latest.version}`));
161
- outro('Done!');
162
- });
163
- }
@@ -1,156 +0,0 @@
1
- // oxlint-disable no-unused-vars
2
- // oxlint-disable no-console
3
- import pc from 'picocolors';
4
-
5
- import { CloudflaredManager } from './cloudflared.js';
6
- import { isUnixLike } from './os-detector.js';
7
- import type { DaemonAction, DaemonConfig } from './types.js';
8
-
9
- export abstract class BaseAdapter {
10
- /**
11
- * Properties
12
- */
13
- abstract get hasDaemonSupport(): boolean;
14
- abstract get isInstalled(): boolean;
15
- abstract get isActive(): boolean;
16
-
17
- /**
18
- * Checks if the user is running as root (only relevant for unix-like).
19
- */
20
- get isRoot(): boolean {
21
- return isUnixLike() && process.getuid?.() === 0;
22
- }
23
-
24
- /**
25
- * Subclasses can override this if a command needs privilege escalation.
26
- */
27
- protected requiresPrivilegeEscalation(action: DaemonAction): boolean {
28
- return false;
29
- }
30
-
31
- /**
32
- * If requiresPrivilegeEscalation returns true, this is called.
33
- */
34
- protected escalatePrivileges(): void {
35
- console.error(
36
- pc.red(
37
- 'Privilege escalation is required for this action but not implemented for this platform.'
38
- )
39
- );
40
- process.exit(1);
41
- }
42
-
43
- /**
44
- * Template Method handling the standard control flow for all OS daemons.
45
- */
46
- public async handleDaemonAction(
47
- action: DaemonAction,
48
- config: DaemonConfig
49
- ): Promise<void> {
50
- if (!this.hasDaemonSupport) {
51
- console.log(
52
- pc.yellow('\nDaemon mode is not supported on this platform.\n')
53
- );
54
- process.exit(1);
55
- }
56
-
57
- if (this.requiresPrivilegeEscalation(action)) {
58
- return this.escalatePrivileges();
59
- }
60
-
61
- switch (action) {
62
- case 'install':
63
- console.log(pc.cyan('Ensuring Cloudflared is installed...'));
64
- CloudflaredManager.install();
65
-
66
- if (this.isInstalled) {
67
- console.log(
68
- pc.yellow(
69
- 'Daemon is already installed. Use "fluxy daemon restart" if needed.'
70
- )
71
- );
72
- return;
73
- }
74
-
75
- console.log(pc.cyan('Installing service...'));
76
- this.installService(config);
77
- console.log(pc.green('✓ Daemon installed and started.'));
78
- break;
79
-
80
- case 'start':
81
- if (!this.isInstalled) {
82
- console.error(
83
- pc.red(
84
- 'Daemon is not installed. Run `fluxy daemon install` first.'
85
- )
86
- );
87
- process.exit(1);
88
- }
89
- if (this.isActive) {
90
- console.log(pc.yellow('Daemon is already running.'));
91
- return;
92
- }
93
- console.log(pc.cyan('Starting daemon...'));
94
- this.startService();
95
- console.log(pc.green('✓ Daemon started.'));
96
- break;
97
-
98
- case 'stop':
99
- if (!this.isInstalled) {
100
- console.error(pc.red('Daemon is not installed.'));
101
- process.exit(1);
102
- }
103
- console.log(pc.cyan('Stopping daemon...'));
104
- this.stopService();
105
- console.log(pc.green('✓ Daemon stopped.'));
106
- break;
107
-
108
- case 'restart':
109
- if (!this.isInstalled) {
110
- console.error(pc.red('Daemon is not installed.'));
111
- process.exit(1);
112
- }
113
- console.log(pc.cyan('Restarting daemon...'));
114
- this.stopService();
115
- this.startService();
116
- console.log(pc.green('✓ Daemon restarted.'));
117
- break;
118
-
119
- case 'status':
120
- this.checkStatus();
121
- break;
122
-
123
- case 'logs':
124
- if (!this.isInstalled) {
125
- console.error(pc.red('Daemon is not installed.'));
126
- process.exit(1);
127
- }
128
- this.showLogs();
129
- break;
130
-
131
- case 'uninstall':
132
- if (!this.isInstalled) {
133
- console.log(pc.yellow('Daemon is not installed.'));
134
- return;
135
- }
136
- console.log(pc.cyan('Uninstalling daemon...'));
137
- this.uninstallService();
138
- console.log(pc.green('✓ Daemon uninstalled.'));
139
- break;
140
-
141
- default:
142
- console.error(pc.red(`Unknown daemon action: ${action}`));
143
- process.exit(1);
144
- }
145
- }
146
-
147
- /**
148
- * OS-specific implementation hooks
149
- */
150
- protected abstract installService(config: DaemonConfig): void;
151
- protected abstract startService(): void;
152
- protected abstract stopService(): void;
153
- protected abstract uninstallService(): void;
154
- protected abstract showLogs(): void;
155
- protected abstract checkStatus(): void;
156
- }
@@ -1,113 +0,0 @@
1
- import fs from 'node:fs';
2
- import { execSync, spawnSync } from 'node:child_process';
3
-
4
- import {
5
- getNormalizedArchitecture,
6
- getPlatform,
7
- isWindows
8
- } from './os-detector.js';
9
- import { BIN_DIR, CF_PATH } from './config.js';
10
-
11
- export class CloudflaredManager {
12
- /**
13
- * Determines the correct download URL for Cloudflared based on OS and Arch.
14
- */
15
- static getDownloadUrl(): string {
16
- const arch = getNormalizedArchitecture();
17
- const platform = getPlatform();
18
-
19
- const baseUrl =
20
- 'https://github.com/cloudflare/cloudflared/releases/latest/download';
21
-
22
- if (platform === 'darwin') {
23
- return `${baseUrl}/cloudflared-darwin-${arch}.tgz`;
24
- }
25
-
26
- if (platform === 'win32') {
27
- return `${baseUrl}/cloudflared-windows-${arch}.exe`;
28
- }
29
-
30
- // Linux default
31
- return `${baseUrl}/cloudflared-linux-${arch}`;
32
- }
33
-
34
- /**
35
- * Checks if a valid cloudflared binary is available (either system-wide or locally).
36
- */
37
- static hasBinary(): boolean {
38
- // 1. Try system-wide
39
- try {
40
- execSync('cloudflared --version', { stdio: 'ignore' });
41
- return true;
42
- } catch {
43
- // not installed globally
44
- }
45
-
46
- // 2. Try local
47
- if (fs.existsSync(CF_PATH)) {
48
- const stats = fs.statSync(CF_PATH);
49
- if (stats.size > 10 * 1024 * 1024) {
50
- // >10MB
51
- return true;
52
- }
53
- }
54
-
55
- return false;
56
- }
57
-
58
- /**
59
- * Installs the local cloudflared binary if required.
60
- */
61
- static install(): void {
62
- if (this.hasBinary()) return;
63
-
64
- const url = this.getDownloadUrl();
65
- fs.mkdirSync(BIN_DIR, { recursive: true });
66
-
67
- if (isWindows()) {
68
- execSync(`curl.exe -fsSL -o "${CF_PATH}" "${url}"`, {
69
- stdio: 'inherit'
70
- });
71
- return;
72
- }
73
-
74
- if (url.endsWith('.tgz')) {
75
- execSync(`curl -fsSL "${url}" | tar xz -C "${BIN_DIR}"`, {
76
- stdio: 'inherit'
77
- });
78
- return;
79
- }
80
-
81
- execSync(`curl -fsSL -o "${CF_PATH}" "${url}"`, { stdio: 'inherit' });
82
- fs.chmodSync(CF_PATH, 0o755);
83
- }
84
-
85
- /**
86
- * Executes cloudflared with the correct binary, trying system first, then local.
87
- */
88
- static spawn(args: string[], options: any = {}) {
89
- try {
90
- // Check if global exists by running it with --version
91
- execSync('cloudflared --version', { stdio: 'ignore' });
92
- return spawnSync('cloudflared', args, options);
93
- } catch {
94
- // Use local
95
- if (!this.hasBinary()) {
96
- this.install();
97
- }
98
- return spawnSync(CF_PATH, args, options);
99
- }
100
- }
101
-
102
- static exec(command: string, options: any = {}) {
103
- try {
104
- execSync('cloudflared --version', { stdio: 'ignore' });
105
- return execSync(`cloudflared ${command}`, options);
106
- } catch {
107
- if (!this.hasBinary()) {
108
- this.install();
109
- }
110
- return execSync(`"${CF_PATH}" ${command}`, options);
111
- }
112
- }
113
- }
@@ -1,73 +0,0 @@
1
- import fs from 'node:fs';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import url from 'node:url';
5
-
6
- import type { BotConfig } from '../../shared/config.js';
7
-
8
- export const PLATFORM = os.platform();
9
-
10
- const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
11
- export const REPO_ROOT = path.resolve(__dirname, '../..');
12
-
13
- export const DATA_DIR = path.join(
14
- process.env.FLUXY_REAL_HOME || os.homedir(),
15
- '.fluxy'
16
- );
17
-
18
- export const IS_DEV = fs.existsSync(path.join(REPO_ROOT, '.git'));
19
- export const ROOT = IS_DEV ? REPO_ROOT : DATA_DIR;
20
- export const CONFIG_PATH = path.join(DATA_DIR, 'config.json');
21
- export const BIN_DIR = path.join(DATA_DIR, 'bin');
22
- export const CF_PATH = path.join(
23
- BIN_DIR,
24
- 'cloudflared' + (PLATFORM === 'win32' ? '.exe' : '')
25
- );
26
-
27
- export const SERVICE_NAME = 'fluxy';
28
-
29
- export const pkg = JSON.parse(
30
- fs.readFileSync(path.join(ROOT, 'package.json'), 'utf-8')
31
- );
32
-
33
- export function loadConfig(): BotConfig {
34
- return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
35
- }
36
-
37
- export function createConfig() {
38
- fs.mkdirSync(DATA_DIR, { recursive: true });
39
- if (fs.existsSync(CONFIG_PATH)) {
40
- return;
41
- }
42
-
43
- const config: Partial<BotConfig> = {
44
- port: 3000,
45
- username: '',
46
- ai: {
47
- provider: '',
48
- model: '',
49
- apiKey: ''
50
- },
51
- tunnel: {
52
- mode: 'quick'
53
- },
54
- relay: {
55
- token: '',
56
- tier: '',
57
- url: ''
58
- }
59
- };
60
- fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
61
- }
62
-
63
- export function safeLoadConfig(fallback: Partial<BotConfig> = {}): BotConfig {
64
- if (!fs.existsSync(CONFIG_PATH)) {
65
- return fallback as BotConfig;
66
- }
67
-
68
- try {
69
- return loadConfig();
70
- } catch {
71
- return fallback as BotConfig;
72
- }
73
- }
@@ -1,43 +0,0 @@
1
- import os from 'node:os';
2
-
3
- export function getPlatform(): string {
4
- return os.platform();
5
- }
6
-
7
- export function isWindows(): boolean {
8
- return getPlatform() === 'win32';
9
- }
10
-
11
- export function isUnixLike(): boolean {
12
- return getPlatform() !== 'win32';
13
- }
14
-
15
- export function getRawArchitecture(): string {
16
- return (process.env.PROCESSOR_ARCHITECTURE || os.arch()).toLowerCase();
17
- }
18
-
19
- /**
20
- * Normalizes the architecture specifically for cloudflared download links.
21
- */
22
- export function getNormalizedArchitecture(): string {
23
- const rawArch = getRawArchitecture();
24
-
25
- if (['arm64', 'aarch64'].includes(rawArch)) {
26
- return 'arm64';
27
- }
28
-
29
- if (['arm', 'armv7l'].includes(rawArch)) {
30
- return 'arm';
31
- }
32
-
33
- if (rawArch === 'x64' || rawArch === 'amd64' || rawArch === 'x86_64') {
34
- return 'amd64';
35
- }
36
-
37
- if (rawArch === '386' || rawArch === 'ia32' || rawArch === 'x86') {
38
- return '386';
39
- }
40
-
41
- // Default fallback
42
- return 'amd64';
43
- }
@@ -1,109 +0,0 @@
1
- import { spawn, type ChildProcess } from 'node:child_process';
2
- import path from 'node:path';
3
- import fs from 'node:fs';
4
- import { ROOT, CONFIG_PATH, type BotConfig } from './config.ts';
5
-
6
- export interface BootResult {
7
- child: ChildProcess;
8
- tunnelUrl: string;
9
- relayUrl: string | null;
10
- tunnelFailed: boolean;
11
- viteWarm: Promise<void>;
12
- }
13
-
14
- export function bootServer({
15
- onTunnelUp,
16
- onReady
17
- }: {
18
- onTunnelUp?: (url?: string) => void;
19
- onReady?: () => void;
20
- } = {}): Promise<BootResult> {
21
- return new Promise(resolve => {
22
- const child = spawn(
23
- process.execPath,
24
- ['--import', 'tsx/esm', path.join(ROOT, 'supervisor/index.ts')],
25
- {
26
- cwd: ROOT,
27
- stdio: ['ignore', 'pipe', 'pipe'],
28
- env: { ...process.env }
29
- }
30
- );
31
-
32
- let tunnelUrl: string | undefined;
33
- let relayUrl: string | undefined;
34
- let resolved = false;
35
- let tunnelFired = false;
36
- let tunnelFailed = false;
37
-
38
- // Vite warmup tracking
39
- let viteWarmResolve: (value: void | PromiseLike<void>) => void;
40
- const viteWarm = new Promise<void>(resolve => {
41
- viteWarmResolve = resolve as any;
42
- });
43
-
44
- const doResolve = () => {
45
- if (resolved) return;
46
- resolved = true;
47
-
48
- if (!tunnelFired && onTunnelUp) {
49
- onTunnelUp();
50
- }
51
- if (onReady) {
52
- onReady();
53
- }
54
-
55
- let config: Partial<BotConfig> = {};
56
- if (fs.existsSync(CONFIG_PATH)) {
57
- config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
58
- }
59
-
60
- resolve({
61
- child,
62
- tunnelUrl:
63
- tunnelUrl || `http://localhost:${config.port || 3000}`,
64
- relayUrl: relayUrl || config.relay?.url || null,
65
- tunnelFailed,
66
- viteWarm
67
- });
68
- };
69
-
70
- const handleData = (data: any) => {
71
- const text = data.toString();
72
-
73
- const tunnelMatch = text.match(/__TUNNEL_URL__=(\S+)/);
74
- if (tunnelMatch) {
75
- tunnelUrl = tunnelMatch[1];
76
- if (!tunnelFired && onTunnelUp) {
77
- tunnelFired = true;
78
- onTunnelUp(tunnelUrl);
79
- }
80
- }
81
-
82
- const relayMatch = text.match(/__RELAY_URL__=(\S+)/);
83
- if (relayMatch) relayUrl = relayMatch[1];
84
-
85
- if (text.includes('__VITE_WARM__')) {
86
- viteWarmResolve();
87
- }
88
-
89
- if (text.includes('__READY__')) {
90
- doResolve();
91
- return;
92
- }
93
-
94
- if (text.includes('__TUNNEL_FAILED__')) {
95
- tunnelFailed = true;
96
- doResolve();
97
- }
98
- };
99
-
100
- // Safety-net timeout
101
- setTimeout(doResolve, 45_000);
102
-
103
- child.stdout?.on('data', handleData);
104
- child.stderr?.on('data', handleData);
105
-
106
- process.on('SIGINT', () => child.kill('SIGINT'));
107
- process.on('SIGTERM', () => child.kill('SIGTERM'));
108
- });
109
- }
package/cli/core/types.ts DELETED
@@ -1,15 +0,0 @@
1
- export type DaemonAction =
2
- | 'install'
3
- | 'stop'
4
- | 'start'
5
- | 'restart'
6
- | 'status'
7
- | 'logs'
8
- | 'uninstall';
9
-
10
- export interface DaemonConfig {
11
- user: string;
12
- home: string;
13
- nodePath: string;
14
- dataDir: string;
15
- }