@fmode/studio 0.0.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/README.md +208 -0
- package/bin/fmode.js +350 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# @fmode/studio
|
|
2
|
+
|
|
3
|
+
**AI PaaS IDE for Vibe Coding** - A cross-platform CLI tool that provides a powerful development environment powered by AI.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
The fastest way to get started is using npx (no installation required):
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx -y @fmode/studio
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This will:
|
|
14
|
+
1. Download and run the latest version automatically
|
|
15
|
+
2. Start the development server on port 16666
|
|
16
|
+
3. Open your browser to the IDE
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
### Global Installation (Recommended for frequent use)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install -g @fmode/studio
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Once installed, you can run:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
fmode
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Using npx (Run without installing)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx @fmode/studio
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### Basic Usage
|
|
41
|
+
|
|
42
|
+
Start the server with default settings (port 16666, host 0.0.0.0):
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
fmode
|
|
46
|
+
# or
|
|
47
|
+
npx @fmode/studio
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Custom Port
|
|
51
|
+
|
|
52
|
+
Start on a specific port:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
fmode --port 16666
|
|
56
|
+
# or
|
|
57
|
+
npx @fmode/studio --port 16666
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Custom Host
|
|
61
|
+
|
|
62
|
+
Start on a specific host:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
fmode --host localhost --port 16666
|
|
66
|
+
# or
|
|
67
|
+
npx @fmode/studio --host localhost --port 16666
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Environment Variables
|
|
71
|
+
|
|
72
|
+
You can also configure the server using environment variables:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
PORT=16666 HOST=localhost fmode
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Available environment variables:
|
|
79
|
+
- `PORT` - Server port (default: 16666)
|
|
80
|
+
- `HOST` - Server host (default: 0.0.0.0)
|
|
81
|
+
- `VITE_IS_PLATFORM` - Set to 'true' for platform mode
|
|
82
|
+
|
|
83
|
+
## Command Line Options
|
|
84
|
+
|
|
85
|
+
| Option | Alias | Description |
|
|
86
|
+
|--------|-------|-------------|
|
|
87
|
+
| `--port <PORT>` | `-p` | Set the server port (default: 16666) |
|
|
88
|
+
| `--host <HOST>` | `-h` | Set the server host (default: 0.0.0.0) |
|
|
89
|
+
| `--help` | | Show help message |
|
|
90
|
+
| `--version` | `-v` | Show version information |
|
|
91
|
+
| `-y` | | Auto-confirm (used with npx) |
|
|
92
|
+
|
|
93
|
+
## Examples
|
|
94
|
+
|
|
95
|
+
### Development Workflow
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Start the development server
|
|
99
|
+
fmode
|
|
100
|
+
|
|
101
|
+
# Start on port 16666 for local development
|
|
102
|
+
fmode --port 16666
|
|
103
|
+
|
|
104
|
+
# Start on localhost only
|
|
105
|
+
fmode --host localhost --port 16666
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### With npx (No Installation)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Quick start with auto-confirm
|
|
112
|
+
npx -y @fmode/studio
|
|
113
|
+
|
|
114
|
+
# Specify custom port
|
|
115
|
+
npx @fmode/studio --port 16666
|
|
116
|
+
|
|
117
|
+
# Full options
|
|
118
|
+
npx @fmode/studio --host localhost --port 16666
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Platform Support
|
|
122
|
+
|
|
123
|
+
@fmode/studio provides native executables for the following platforms:
|
|
124
|
+
|
|
125
|
+
| Platform | Architecture | Executable |
|
|
126
|
+
|----------|--------------|------------|
|
|
127
|
+
| Windows | x64 | fmode-win-x64.exe |
|
|
128
|
+
| Windows | ARM64 | fmode-win-arm64.exe |
|
|
129
|
+
| Linux | x64 | fmode-linux-x64 |
|
|
130
|
+
| Linux | ARM64 | fmode-linux-arm64 |
|
|
131
|
+
| macOS | x64 (Intel) | fmode-macos-x64 |
|
|
132
|
+
| macOS | ARM64 (Apple Silicon) | fmode-macos-arm64 |
|
|
133
|
+
|
|
134
|
+
The CLI automatically detects your platform and uses the appropriate executable.
|
|
135
|
+
|
|
136
|
+
## Requirements
|
|
137
|
+
|
|
138
|
+
- **Node.js**: >= 18.0.0
|
|
139
|
+
- **Bun**: >= 1.0.0 (optional, for development)
|
|
140
|
+
- **OS**: Windows, macOS, or Linux
|
|
141
|
+
- **CPU**: x64 or ARM64
|
|
142
|
+
|
|
143
|
+
## Data Storage
|
|
144
|
+
|
|
145
|
+
Application data is stored in your user data directory:
|
|
146
|
+
|
|
147
|
+
- **Windows**: `%APPDATA%\fmode-studio`
|
|
148
|
+
- **macOS**: `~/Library/Application Support/fmode-studio`
|
|
149
|
+
- **Linux**: `~/.config/fmode-studio`
|
|
150
|
+
|
|
151
|
+
## Troubleshooting
|
|
152
|
+
|
|
153
|
+
### Port Already in Use
|
|
154
|
+
|
|
155
|
+
If you see an error that the port is already in use:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
fmode --port 16666
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Permission Issues
|
|
162
|
+
|
|
163
|
+
On Linux/macOS, if you get permission errors, make sure the executable has execute permissions:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
chmod +x node_modules/@fmode/studio/dist/bin/fmode-*
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Fallback to Node.js
|
|
170
|
+
|
|
171
|
+
If the native executable is not available for your platform, the CLI will automatically fall back to running with Bun (if installed).
|
|
172
|
+
|
|
173
|
+
## Version Check
|
|
174
|
+
|
|
175
|
+
Check your installed version:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
fmode --version
|
|
179
|
+
# or
|
|
180
|
+
npx @fmode/studio --version
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Help
|
|
184
|
+
|
|
185
|
+
Display help information:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
fmode --help
|
|
189
|
+
# or
|
|
190
|
+
npx @fmode/studio --help
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## License
|
|
194
|
+
|
|
195
|
+
© 2026 未来飞马® All rights reserved.
|
|
196
|
+
|
|
197
|
+
## Author
|
|
198
|
+
|
|
199
|
+
Fmode Studio
|
|
200
|
+
|
|
201
|
+
- [Fmode Inc](https://www.npmjs.com/~fmode)
|
|
202
|
+
- [RyaneMax](https://github.com/ryanemax)
|
|
203
|
+
|
|
204
|
+
## Links
|
|
205
|
+
|
|
206
|
+
- Repository: https://www.npmjs.com/package/@fmode/studio
|
|
207
|
+
- Issues: https://app.fmode.cn/dev/studio
|
|
208
|
+
|
package/bin/fmode.js
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fmode Studio CLI Entry Point
|
|
5
|
+
* npm/npx compatible entry point
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Version checking against repos.fmode.cn
|
|
9
|
+
* - Automatic binary download and caching
|
|
10
|
+
* - Update command for manual updates
|
|
11
|
+
* - Fallback to Node.js/Bun execution
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* npx @fmode/studio
|
|
15
|
+
* npx @fmode/studio -y
|
|
16
|
+
* npx @fmode/studio update
|
|
17
|
+
* fmode
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { spawn } from 'child_process';
|
|
21
|
+
import { fileURLToPath } from 'url';
|
|
22
|
+
import { dirname, join } from 'path';
|
|
23
|
+
import { existsSync, mkdirSync, chmodSync, renameSync } from 'fs';
|
|
24
|
+
import { createReadStream, createWriteStream } from 'fs';
|
|
25
|
+
import { pipeline } from 'stream/promises';
|
|
26
|
+
import { unlink, readFile } from 'fs/promises';
|
|
27
|
+
|
|
28
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
29
|
+
const __dirname = dirname(__filename);
|
|
30
|
+
const rootDir = dirname(__dirname);
|
|
31
|
+
|
|
32
|
+
// Configuration
|
|
33
|
+
const REPOS_BASE_URL = 'https://repos.fmode.cn/x/fmode-studio';
|
|
34
|
+
const MANIFEST_URL = `${REPOS_BASE_URL}/manifest.json`;
|
|
35
|
+
const CACHE_DIR = join(rootDir, '.cache', 'binaries');
|
|
36
|
+
|
|
37
|
+
// Platform detection
|
|
38
|
+
const platform = process.platform;
|
|
39
|
+
const arch = process.arch;
|
|
40
|
+
|
|
41
|
+
// Map platform/arch to executable name
|
|
42
|
+
function getExecutableName() {
|
|
43
|
+
const ext = platform === 'win32' ? '.exe' : '';
|
|
44
|
+
|
|
45
|
+
if (platform === 'win32' && arch === 'x64') {
|
|
46
|
+
return `fmode-win-x64${ext}`;
|
|
47
|
+
} else if (platform === 'win32' && arch === 'arm64') {
|
|
48
|
+
return `fmode-win-arm64${ext}`;
|
|
49
|
+
} else if (platform === 'linux' && arch === 'x64') {
|
|
50
|
+
return 'fmode-linux-x64';
|
|
51
|
+
} else if (platform === 'linux' && arch === 'arm64') {
|
|
52
|
+
return 'fmode-linux-arm64';
|
|
53
|
+
} else if (platform === 'darwin' && arch === 'x64') {
|
|
54
|
+
return 'fmode-macos-x64';
|
|
55
|
+
} else if (platform === 'darwin' && arch === 'arm64') {
|
|
56
|
+
return 'fmode-macos-arm64';
|
|
57
|
+
} else {
|
|
58
|
+
throw new Error(`Unsupported platform: ${platform} ${arch}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Get local package version
|
|
63
|
+
async function getLocalVersion() {
|
|
64
|
+
const packageJson = join(rootDir, 'package.json');
|
|
65
|
+
try {
|
|
66
|
+
const content = await readFile(packageJson, 'utf-8');
|
|
67
|
+
const pkg = JSON.parse(content);
|
|
68
|
+
return pkg.version;
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Fetch remote manifest from repos.fmode.cn
|
|
75
|
+
async function fetchRemoteManifest() {
|
|
76
|
+
try {
|
|
77
|
+
const response = await fetch(MANIFEST_URL);
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
throw new Error(`HTTP ${response.status}`);
|
|
80
|
+
}
|
|
81
|
+
return await response.json();
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.warn(`Warning: Could not fetch remote manifest: ${error.message}`);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Compare versions (returns positive if a > b, negative if a < b, 0 if equal)
|
|
89
|
+
function compareVersions(a, b) {
|
|
90
|
+
const partsA = a.split('.').map(Number);
|
|
91
|
+
const partsB = b.split('.').map(Number);
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
|
94
|
+
const partA = partsA[i] || 0;
|
|
95
|
+
const partB = partsB[i] || 0;
|
|
96
|
+
if (partA !== partB) {
|
|
97
|
+
return partA - partB;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Download binary from repos.fmode.cn
|
|
104
|
+
async function downloadBinary(version, executableName) {
|
|
105
|
+
const url = `${REPOS_BASE_URL}/${version}/${executableName}`;
|
|
106
|
+
const tempPath = join(CACHE_DIR, `${executableName}.tmp`);
|
|
107
|
+
const finalPath = join(CACHE_DIR, executableName);
|
|
108
|
+
|
|
109
|
+
console.log(`Downloading ${url}...`);
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const response = await fetch(url);
|
|
113
|
+
if (!response.ok) {
|
|
114
|
+
throw new Error(`HTTP ${response.status}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Ensure cache directory exists
|
|
118
|
+
if (!existsSync(CACHE_DIR)) {
|
|
119
|
+
mkdirSync(CACHE_DIR, { recursive: true });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Download to temp file
|
|
123
|
+
const fileStream = createWriteStream(tempPath);
|
|
124
|
+
await pipeline(response.body, fileStream);
|
|
125
|
+
|
|
126
|
+
// Make executable (Unix-like systems)
|
|
127
|
+
if (platform !== 'win32') {
|
|
128
|
+
chmodSync(tempPath, 0o755);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Move to final path
|
|
132
|
+
if (existsSync(finalPath)) {
|
|
133
|
+
await unlink(finalPath);
|
|
134
|
+
}
|
|
135
|
+
renameSync(tempPath, finalPath);
|
|
136
|
+
|
|
137
|
+
console.log(`Downloaded to ${finalPath}`);
|
|
138
|
+
return finalPath;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
// Clean up temp file on error
|
|
141
|
+
if (existsSync(tempPath)) {
|
|
142
|
+
await unlink(tempPath).catch(() => {});
|
|
143
|
+
}
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Check for updates
|
|
149
|
+
async function checkForUpdates() {
|
|
150
|
+
const localVersion = await getLocalVersion();
|
|
151
|
+
const manifest = await fetchRemoteManifest();
|
|
152
|
+
|
|
153
|
+
if (!manifest || !manifest.version) {
|
|
154
|
+
console.log('Could not check for updates.');
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!localVersion) {
|
|
159
|
+
console.log(`Remote version: ${manifest.version}`);
|
|
160
|
+
console.log('Local version: unknown');
|
|
161
|
+
return manifest.version;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const comparison = compareVersions(manifest.version, localVersion);
|
|
165
|
+
|
|
166
|
+
if (comparison > 0) {
|
|
167
|
+
console.log(`Update available: ${localVersion} -> ${manifest.version}`);
|
|
168
|
+
return manifest.version;
|
|
169
|
+
} else if (comparison === 0) {
|
|
170
|
+
console.log(`Already up to date: ${localVersion}`);
|
|
171
|
+
return null;
|
|
172
|
+
} else {
|
|
173
|
+
console.log(`Local version is newer: ${localVersion} > ${manifest.version}`);
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Run the executable
|
|
179
|
+
async function runExecutable(executablePath, args) {
|
|
180
|
+
const child = spawn(executablePath, args, {
|
|
181
|
+
stdio: 'inherit',
|
|
182
|
+
env: { ...process.env }
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return new Promise((resolve, reject) => {
|
|
186
|
+
child.on('exit', (code) => {
|
|
187
|
+
resolve(code ?? 0);
|
|
188
|
+
process.exit(code ?? 0);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
child.on('error', (err) => {
|
|
192
|
+
reject(err);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Main execution
|
|
198
|
+
async function main() {
|
|
199
|
+
const args = process.argv.slice(2);
|
|
200
|
+
|
|
201
|
+
// Handle -y flag (auto-confirm, no-op in our case)
|
|
202
|
+
const yesIndex = args.indexOf('-y');
|
|
203
|
+
if (yesIndex !== -1) {
|
|
204
|
+
args.splice(yesIndex, 1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Handle update command
|
|
208
|
+
if (args[0] === 'update') {
|
|
209
|
+
console.log('Checking for updates...');
|
|
210
|
+
const newVersion = await checkForUpdates();
|
|
211
|
+
|
|
212
|
+
if (newVersion) {
|
|
213
|
+
const executableName = getExecutableName();
|
|
214
|
+
console.log(`\nDownloading version ${newVersion}...`);
|
|
215
|
+
try {
|
|
216
|
+
await downloadBinary(newVersion, executableName);
|
|
217
|
+
console.log('\n✓ Update complete!');
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error(`\n✗ Download failed: ${error.message}`);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
process.exit(0);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Handle --version flag
|
|
227
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
228
|
+
const localVersion = await getLocalVersion();
|
|
229
|
+
if (localVersion) {
|
|
230
|
+
console.log(`@fmode/studio v${localVersion}`);
|
|
231
|
+
} else {
|
|
232
|
+
console.log('@fmode/studio (version unknown)');
|
|
233
|
+
}
|
|
234
|
+
process.exit(0);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Handle --help flag
|
|
238
|
+
if (args.includes('--help') || (args.includes('-h') && !args.includes('--host'))) {
|
|
239
|
+
console.log(`
|
|
240
|
+
Fmode Code UI Server
|
|
241
|
+
|
|
242
|
+
USAGE:
|
|
243
|
+
fmode [OPTIONS]
|
|
244
|
+
npx @fmode/studio [OPTIONS]
|
|
245
|
+
fmode update Check and install updates
|
|
246
|
+
|
|
247
|
+
OPTIONS:
|
|
248
|
+
-p, --port <PORT> Set the server port (default: 6666)
|
|
249
|
+
-h, --host <HOST> Set the server host (default: 0.0.0.0)
|
|
250
|
+
--help Show this help message
|
|
251
|
+
--version, -v Show version information
|
|
252
|
+
-y Auto-confirm (no-op, for compatibility)
|
|
253
|
+
update Check and install updates
|
|
254
|
+
|
|
255
|
+
ENVIRONMENT VARIABLES:
|
|
256
|
+
PORT Server port (default: 6666)
|
|
257
|
+
HOST Server host (default: 0.0.0.0)
|
|
258
|
+
VITE_IS_PLATFORM Set to 'true' for platform mode
|
|
259
|
+
|
|
260
|
+
EXAMPLES:
|
|
261
|
+
fmode # Start with default settings
|
|
262
|
+
fmode --port 8080 # Start on port 8080
|
|
263
|
+
npx @fmode/studio -y # Start with npx (auto-confirm)
|
|
264
|
+
npx @fmode/studio --port 3000 # Start on port 3000
|
|
265
|
+
fmode update # Check for updates
|
|
266
|
+
|
|
267
|
+
UPDATE MECHANISM:
|
|
268
|
+
The CLI automatically downloads the latest binary from repos.fmode.cn
|
|
269
|
+
and caches it locally. Use 'fmode update' to manually check for updates.
|
|
270
|
+
`);
|
|
271
|
+
process.exit(0);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const executableName = getExecutableName();
|
|
275
|
+
let executablePath = null;
|
|
276
|
+
|
|
277
|
+
// Priority 1: Try cached binary (most recent download)
|
|
278
|
+
const cachedPath = join(CACHE_DIR, executableName);
|
|
279
|
+
if (existsSync(cachedPath)) {
|
|
280
|
+
executablePath = cachedPath;
|
|
281
|
+
console.log(`Using cached binary: ${cachedPath}`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Priority 2: Try bundled binary (shipped with npm package)
|
|
285
|
+
if (!executablePath) {
|
|
286
|
+
const bundledPath = join(rootDir, 'dist', 'bin', executableName);
|
|
287
|
+
if (existsSync(bundledPath)) {
|
|
288
|
+
executablePath = bundledPath;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Priority 3: Download from repos.fmode.cn
|
|
293
|
+
if (!executablePath) {
|
|
294
|
+
console.log('No local binary found. Downloading...');
|
|
295
|
+
try {
|
|
296
|
+
const manifest = await fetchRemoteManifest();
|
|
297
|
+
if (manifest && manifest.version) {
|
|
298
|
+
executablePath = await downloadBinary(manifest.version, executableName);
|
|
299
|
+
}
|
|
300
|
+
} catch (error) {
|
|
301
|
+
console.warn(`Could not download binary: ${error.message}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// If we have an executable, run it
|
|
306
|
+
if (executablePath) {
|
|
307
|
+
try {
|
|
308
|
+
await runExecutable(executablePath, args);
|
|
309
|
+
return;
|
|
310
|
+
} catch (err) {
|
|
311
|
+
console.error('Failed to start native executable:', err.message);
|
|
312
|
+
// Fall through to Node.js/Bun fallback
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Priority 4: Fallback to Node.js/Bun
|
|
317
|
+
fallbackToNode(args);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function fallbackToNode(args) {
|
|
321
|
+
const cliPath = join(rootDir, 'cli.ts');
|
|
322
|
+
|
|
323
|
+
if (existsSync(cliPath)) {
|
|
324
|
+
console.log('Running with bun...');
|
|
325
|
+
const child = spawn('bun', [cliPath, ...args], {
|
|
326
|
+
stdio: 'inherit',
|
|
327
|
+
env: { ...process.env }
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
child.on('exit', (code) => {
|
|
331
|
+
process.exit(code ?? 0);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
child.on('error', (err) => {
|
|
335
|
+
console.error('Failed to start with bun:', err.message);
|
|
336
|
+
console.error('Please install bun: https://bun.sh');
|
|
337
|
+
process.exit(1);
|
|
338
|
+
});
|
|
339
|
+
} else {
|
|
340
|
+
console.error(`Error: Fmode Studio not found for platform ${platform} ${arch}`);
|
|
341
|
+
console.error('Please reinstall the package or report this issue.');
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Run main function
|
|
347
|
+
main().catch((error) => {
|
|
348
|
+
console.error('Fatal error:', error);
|
|
349
|
+
process.exit(1);
|
|
350
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fmode/studio",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "AI PaaS IDE for Vibe Coding - Cross-platform CLI tool",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "Fmode Studio Team",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"fmode": "./bin/fmode.js",
|
|
10
|
+
"@fmode/studio": "./bin/fmode.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"bin",
|
|
15
|
+
"*.js",
|
|
16
|
+
"api"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18.0.0",
|
|
20
|
+
"bun": ">=1.0.0"
|
|
21
|
+
},
|
|
22
|
+
"os": [
|
|
23
|
+
"darwin",
|
|
24
|
+
"linux",
|
|
25
|
+
"win32"
|
|
26
|
+
],
|
|
27
|
+
"cpu": [
|
|
28
|
+
"x64",
|
|
29
|
+
"arm64"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@aws-sdk/client-s3": "^3.965.0",
|
|
33
|
+
"@siteboon/claude-code-ui": "^1.13.6",
|
|
34
|
+
"bun-pty": "^0.4.6"
|
|
35
|
+
}
|
|
36
|
+
}
|