@frontman-ai/vite 0.1.0 → 0.1.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 +235 -0
- package/dist/cli.js +836 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -3
- package/package.json +5 -1
package/README.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# @frontman-ai/vite
|
|
2
|
+
|
|
3
|
+
Vite integration for Frontman - provides AI-powered development tools for any Vite-based application (React, Vue, Svelte, SolidJS, vanilla, etc.).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Quick Install (Recommended)
|
|
8
|
+
|
|
9
|
+
The fastest way to install Frontman is using our CLI installer:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @frontman-ai/vite install
|
|
13
|
+
|
|
14
|
+
# Or with a custom server host
|
|
15
|
+
npx @frontman-ai/vite install --server frontman.company.com
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The installer will:
|
|
19
|
+
- Detect your Vite project and package manager
|
|
20
|
+
- Install `@frontman-ai/vite` as a dev dependency
|
|
21
|
+
- Add `frontmanPlugin()` to your `vite.config.ts` plugins array (or create one)
|
|
22
|
+
|
|
23
|
+
### CLI Options
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx @frontman-ai/vite install [options]
|
|
27
|
+
|
|
28
|
+
Options:
|
|
29
|
+
--server <host> Frontman server host (default: api.frontman.sh)
|
|
30
|
+
--prefix <path> Target directory (default: current directory)
|
|
31
|
+
--dry-run Preview changes without writing files
|
|
32
|
+
--skip-deps Skip dependency installation
|
|
33
|
+
--help Show help message
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Manual Installation
|
|
37
|
+
|
|
38
|
+
If you prefer to set things up manually or need to integrate with an existing configuration:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install -D @frontman-ai/vite
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then follow the [Manual Setup](#manual-setup) instructions below.
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
After running the installer, you're ready to go! Start your Vite dev server:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm run dev
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Then open your browser to `http://localhost:5173/frontman` to access the Frontman UI.
|
|
55
|
+
|
|
56
|
+
## Manual Setup
|
|
57
|
+
|
|
58
|
+
Add the plugin to your `vite.config.ts`:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { defineConfig } from 'vite';
|
|
62
|
+
import { frontmanPlugin } from '@frontman-ai/vite';
|
|
63
|
+
|
|
64
|
+
export default defineConfig({
|
|
65
|
+
plugins: [
|
|
66
|
+
frontmanPlugin(),
|
|
67
|
+
],
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
That's it! The plugin hooks into Vite's dev server and serves the Frontman UI at `/frontman`.
|
|
72
|
+
|
|
73
|
+
## Adding to Existing Config
|
|
74
|
+
|
|
75
|
+
If you already have a `vite.config.ts` with plugins, add `frontmanPlugin()` to your existing plugins array:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { defineConfig } from 'vite';
|
|
79
|
+
import react from '@vitejs/plugin-react';
|
|
80
|
+
import { frontmanPlugin } from '@frontman-ai/vite';
|
|
81
|
+
|
|
82
|
+
export default defineConfig({
|
|
83
|
+
plugins: [
|
|
84
|
+
frontmanPlugin(),
|
|
85
|
+
react(),
|
|
86
|
+
// ...your other plugins
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Installer shows "manual modification required"
|
|
92
|
+
|
|
93
|
+
This happens when the installer can't find a `plugins: [` array in your Vite config. Manually add the import and plugin as shown above.
|
|
94
|
+
|
|
95
|
+
## Configuration Options
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { frontmanPlugin } from '@frontman-ai/vite';
|
|
99
|
+
|
|
100
|
+
frontmanPlugin({
|
|
101
|
+
// All options are optional
|
|
102
|
+
isDev: true, // Development mode (default: NODE_ENV !== "production")
|
|
103
|
+
basePath: 'frontman', // Base path for Frontman routes (default: "frontman")
|
|
104
|
+
host: 'frontman.local:4000', // Frontman server host (default: env FRONTMAN_HOST or "frontman.local:4000")
|
|
105
|
+
clientUrl: 'https://...', // Custom client bundle URL
|
|
106
|
+
clientCssUrl: 'https://...', // Custom client CSS URL
|
|
107
|
+
entrypointUrl: 'http://...', // Custom entrypoint URL for the API
|
|
108
|
+
isLightTheme: false, // Use light theme (default: false / dark)
|
|
109
|
+
projectRoot: '.', // Project root directory (default: env PROJECT_ROOT or cwd)
|
|
110
|
+
sourceRoot: '.', // Source root for resolving file paths (default: projectRoot)
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Understanding the `host` Option
|
|
115
|
+
|
|
116
|
+
The `host` option specifies the Frontman server that the client UI will connect to for AI capabilities. When you visit `/frontman` in your Vite app:
|
|
117
|
+
|
|
118
|
+
1. The plugin serves the Frontman UI HTML
|
|
119
|
+
2. The UI loads the client JavaScript with `?host=<your-host>`
|
|
120
|
+
3. The client establishes a WebSocket connection to `wss://<host>/socket`
|
|
121
|
+
4. AI interactions and tool calls flow through this connection
|
|
122
|
+
|
|
123
|
+
The plugin itself doesn't connect to the Frontman server - it only passes the host to the client.
|
|
124
|
+
|
|
125
|
+
**Examples:**
|
|
126
|
+
- Production: `host: 'api.frontman.sh'` → client connects to `wss://api.frontman.sh/socket`
|
|
127
|
+
- Local dev: `host: 'frontman.local:4000'` → client connects to `wss://frontman.local:4000/socket`
|
|
128
|
+
|
|
129
|
+
## Supported Frameworks
|
|
130
|
+
|
|
131
|
+
This plugin works with any Vite-based project:
|
|
132
|
+
|
|
133
|
+
- React (via `@vitejs/plugin-react`)
|
|
134
|
+
- Vue (via `@vitejs/plugin-vue`)
|
|
135
|
+
- Svelte (via `@sveltejs/vite-plugin-svelte`)
|
|
136
|
+
- SolidJS (via `vite-plugin-solid`)
|
|
137
|
+
- Vanilla JS/TS
|
|
138
|
+
- Any other Vite-compatible framework
|
|
139
|
+
|
|
140
|
+
| Version | Status |
|
|
141
|
+
|---------|--------|
|
|
142
|
+
| Vite 5.x | Fully supported |
|
|
143
|
+
| Vite 6.x | Fully supported |
|
|
144
|
+
|
|
145
|
+
## Architecture
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Vite Dev Server
|
|
149
|
+
│
|
|
150
|
+
├─> configureServer hook
|
|
151
|
+
│ └─> frontmanPlugin registers Connect middleware
|
|
152
|
+
│ └─> Adapts Node.js req/res ↔ Web API Request/Response
|
|
153
|
+
│
|
|
154
|
+
├─> GET /frontman
|
|
155
|
+
│ └─> Serves Frontman UI (HTML + client bundle)
|
|
156
|
+
│ └─> Client connects to Frontman server via WebSocket
|
|
157
|
+
│
|
|
158
|
+
├─> GET /frontman/tools
|
|
159
|
+
│ └─> Returns tool definitions from ToolRegistry
|
|
160
|
+
│ └─> Core tools (file read, write, search, etc.)
|
|
161
|
+
│
|
|
162
|
+
├─> POST /frontman/tools/call
|
|
163
|
+
│ └─> Executes tool → returns SSE stream with results
|
|
164
|
+
│
|
|
165
|
+
└─> POST /frontman/resolve-source-location
|
|
166
|
+
└─> Resolves source maps to original component locations
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Key Technical Details
|
|
170
|
+
|
|
171
|
+
**Node.js ↔ Web API Adapter**
|
|
172
|
+
- Vite's dev server uses Node.js `IncomingMessage`/`ServerResponse`
|
|
173
|
+
- Frontman middleware uses Web API `Request`/`Response`
|
|
174
|
+
- The plugin adapts between the two, including SSE stream piping
|
|
175
|
+
|
|
176
|
+
**Available Endpoints**
|
|
177
|
+
|
|
178
|
+
| Route | Method | Description |
|
|
179
|
+
|-------|--------|-------------|
|
|
180
|
+
| `GET /frontman` | GET | Serves the Frontman UI |
|
|
181
|
+
| `GET /frontman/tools` | GET | Returns available tool definitions |
|
|
182
|
+
| `POST /frontman/tools/call` | POST | Executes a tool call (SSE response) |
|
|
183
|
+
| `POST /frontman/resolve-source-location` | POST | Resolves source maps to original locations |
|
|
184
|
+
| `OPTIONS /frontman/*` | OPTIONS | CORS preflight handling |
|
|
185
|
+
|
|
186
|
+
Non-frontman routes pass through to Vite's normal dev server handling.
|
|
187
|
+
|
|
188
|
+
## Troubleshooting
|
|
189
|
+
|
|
190
|
+
### Frontman UI not loading
|
|
191
|
+
|
|
192
|
+
**Check 1: Verify the plugin is registered**
|
|
193
|
+
Make sure `frontmanPlugin()` is in your `vite.config.ts` plugins array and your dev server is running.
|
|
194
|
+
|
|
195
|
+
**Check 2: Check the URL**
|
|
196
|
+
The default path is `http://localhost:5173/frontman`. If you changed the `basePath` option, use that path instead.
|
|
197
|
+
|
|
198
|
+
**Check 3: Check for port conflicts**
|
|
199
|
+
If Vite is running on a different port, use that port in the URL (e.g., `http://localhost:3000/frontman`).
|
|
200
|
+
|
|
201
|
+
### Installer shows "manual modification required"
|
|
202
|
+
|
|
203
|
+
This happens when the installer can't find a `plugins: [` array in your Vite config to inject into. Manually add the import and plugin call as shown in [Manual Setup](#manual-setup).
|
|
204
|
+
|
|
205
|
+
### CORS errors in browser console
|
|
206
|
+
|
|
207
|
+
The plugin includes CORS headers for all `/frontman/*` routes. If you're seeing CORS errors, verify the request is going to the correct Vite dev server URL.
|
|
208
|
+
|
|
209
|
+
## API
|
|
210
|
+
|
|
211
|
+
### `frontmanPlugin(options?)`
|
|
212
|
+
|
|
213
|
+
Creates a Vite plugin that serves the Frontman UI and tool endpoints on the dev server.
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import { frontmanPlugin } from '@frontman-ai/vite';
|
|
217
|
+
|
|
218
|
+
const plugin = frontmanPlugin({
|
|
219
|
+
host: string, // Frontman server host (default: env FRONTMAN_HOST or "frontman.local:4000")
|
|
220
|
+
basePath: string, // Base path (default: "frontman")
|
|
221
|
+
isDev: boolean, // Dev mode (default: NODE_ENV !== "production")
|
|
222
|
+
projectRoot: string, // Project root (default: env PROJECT_ROOT or cwd)
|
|
223
|
+
sourceRoot: string, // Source root (default: projectRoot)
|
|
224
|
+
clientUrl: string, // Custom client bundle URL
|
|
225
|
+
clientCssUrl: string, // Custom client CSS URL
|
|
226
|
+
entrypointUrl: string, // Custom entrypoint URL
|
|
227
|
+
isLightTheme: boolean, // Light theme (default: false)
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Returns:** A Vite plugin object with `name: "frontman"` and a `configureServer` hook.
|
|
232
|
+
|
|
233
|
+
## License
|
|
234
|
+
|
|
235
|
+
Apache-2.0
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,836 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as Process from 'process';
|
|
3
|
+
import * as Fs from 'fs';
|
|
4
|
+
import * as Nodepath from 'path';
|
|
5
|
+
|
|
6
|
+
// ../../node_modules/@rescript/runtime/lib/es6/Primitive_option.js
|
|
7
|
+
function some(x) {
|
|
8
|
+
if (x === void 0) {
|
|
9
|
+
return {
|
|
10
|
+
BS_PRIVATE_NESTED_SOME_NONE: 0
|
|
11
|
+
};
|
|
12
|
+
} else if (x !== null && x.BS_PRIVATE_NESTED_SOME_NONE !== void 0) {
|
|
13
|
+
return {
|
|
14
|
+
BS_PRIVATE_NESTED_SOME_NONE: x.BS_PRIVATE_NESTED_SOME_NONE + 1 | 0
|
|
15
|
+
};
|
|
16
|
+
} else {
|
|
17
|
+
return x;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function fromNullable(x) {
|
|
21
|
+
if (x == null) {
|
|
22
|
+
return;
|
|
23
|
+
} else {
|
|
24
|
+
return some(x);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function valFromOption(x) {
|
|
28
|
+
if (x === null || x.BS_PRIVATE_NESTED_SOME_NONE === void 0) {
|
|
29
|
+
return x;
|
|
30
|
+
}
|
|
31
|
+
let depth = x.BS_PRIVATE_NESTED_SOME_NONE;
|
|
32
|
+
if (depth === 0) {
|
|
33
|
+
return;
|
|
34
|
+
} else {
|
|
35
|
+
return {
|
|
36
|
+
BS_PRIVATE_NESTED_SOME_NONE: depth - 1 | 0
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ../../node_modules/@rescript/runtime/lib/es6/Stdlib_Option.js
|
|
42
|
+
function mapOr(opt, $$default, f) {
|
|
43
|
+
if (opt !== void 0) {
|
|
44
|
+
return f(valFromOption(opt));
|
|
45
|
+
} else {
|
|
46
|
+
return $$default;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function map(opt, f) {
|
|
50
|
+
if (opt !== void 0) {
|
|
51
|
+
return some(f(valFromOption(opt)));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function flatMap(opt, f) {
|
|
55
|
+
if (opt !== void 0) {
|
|
56
|
+
return f(valFromOption(opt));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function getOr(opt, $$default) {
|
|
60
|
+
if (opt !== void 0) {
|
|
61
|
+
return valFromOption(opt);
|
|
62
|
+
} else {
|
|
63
|
+
return $$default;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function isSome(x) {
|
|
67
|
+
return x !== void 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ../../node_modules/@rescript/runtime/lib/es6/Primitive_exceptions.js
|
|
71
|
+
function isExtension(e) {
|
|
72
|
+
if (e == null) {
|
|
73
|
+
return false;
|
|
74
|
+
} else {
|
|
75
|
+
return typeof e.RE_EXN_ID === "string";
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function internalToException(e) {
|
|
79
|
+
if (isExtension(e)) {
|
|
80
|
+
return e;
|
|
81
|
+
} else {
|
|
82
|
+
return {
|
|
83
|
+
RE_EXN_ID: "JsExn",
|
|
84
|
+
_1: e
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ../bindings/src/ChildProcess.res.mjs
|
|
90
|
+
var execPromise = (async function(command, options) {
|
|
91
|
+
const { exec } = await import('child_process');
|
|
92
|
+
const { promisify } = await import('util');
|
|
93
|
+
const execP = promisify(exec);
|
|
94
|
+
return await execP(command, options);
|
|
95
|
+
});
|
|
96
|
+
var bufferToString = (function(value) {
|
|
97
|
+
if (value == null) return "";
|
|
98
|
+
if (typeof value === "string") return value;
|
|
99
|
+
if (Buffer.isBuffer(value)) return value.toString("utf8");
|
|
100
|
+
return String(value);
|
|
101
|
+
});
|
|
102
|
+
async function execWithOptions(command, options) {
|
|
103
|
+
try {
|
|
104
|
+
let newrecord = { ...options };
|
|
105
|
+
newrecord.maxBuffer = getOr(options.maxBuffer, 52428800);
|
|
106
|
+
let result = await execPromise(command, newrecord);
|
|
107
|
+
return {
|
|
108
|
+
TAG: "Ok",
|
|
109
|
+
_0: {
|
|
110
|
+
stdout: bufferToString(result.stdout),
|
|
111
|
+
stderr: bufferToString(result.stderr)
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
} catch (raw_exn) {
|
|
115
|
+
let exn = internalToException(raw_exn);
|
|
116
|
+
let actualError = getOr(fromNullable(exn._1), exn);
|
|
117
|
+
return {
|
|
118
|
+
TAG: "Error",
|
|
119
|
+
_0: {
|
|
120
|
+
code: fromNullable(actualError.code),
|
|
121
|
+
stdout: getOr(map(fromNullable(actualError.stdout), bufferToString), ""),
|
|
122
|
+
stderr: getOr(map(fromNullable(actualError.stderr), bufferToString), "")
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/cli/FrontmanVite__Cli__Style.res.mjs
|
|
129
|
+
var esc = "\x1B";
|
|
130
|
+
function purple(text) {
|
|
131
|
+
return esc + `[38;2;152;93;247m` + text + esc + `[0m`;
|
|
132
|
+
}
|
|
133
|
+
function purpleBold(text) {
|
|
134
|
+
return esc + `[1;38;2;152;93;247m` + text + esc + `[0m`;
|
|
135
|
+
}
|
|
136
|
+
function purpleDim(text) {
|
|
137
|
+
return esc + `[38;2;128;81;205m` + text + esc + `[0m`;
|
|
138
|
+
}
|
|
139
|
+
function green(text) {
|
|
140
|
+
return esc + `[32m` + text + esc + `[0m`;
|
|
141
|
+
}
|
|
142
|
+
function yellow(text) {
|
|
143
|
+
return esc + `[33m` + text + esc + `[0m`;
|
|
144
|
+
}
|
|
145
|
+
function yellowBold(text) {
|
|
146
|
+
return esc + `[1;33m` + text + esc + `[0m`;
|
|
147
|
+
}
|
|
148
|
+
function bold(text) {
|
|
149
|
+
return esc + `[1m` + text + esc + `[0m`;
|
|
150
|
+
}
|
|
151
|
+
function dim(text) {
|
|
152
|
+
return esc + `[2m` + text + esc + `[0m`;
|
|
153
|
+
}
|
|
154
|
+
var check = green("\u2714");
|
|
155
|
+
var warn = yellow("\u26A0");
|
|
156
|
+
var bullet = purple("\u25B8");
|
|
157
|
+
var divider = purple("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
158
|
+
|
|
159
|
+
// ../../node_modules/@rescript/runtime/lib/es6/Stdlib_JSON.js
|
|
160
|
+
function bool(json) {
|
|
161
|
+
if (typeof json === "boolean") {
|
|
162
|
+
return json;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function $$null(json) {
|
|
166
|
+
if (json === null) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function string(json) {
|
|
171
|
+
if (typeof json === "string") {
|
|
172
|
+
return json;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function float(json) {
|
|
176
|
+
if (typeof json === "number") {
|
|
177
|
+
return json;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function object(json) {
|
|
181
|
+
if (typeof json === "object" && json !== null && !Array.isArray(json)) {
|
|
182
|
+
return json;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function array(json) {
|
|
186
|
+
if (Array.isArray(json)) {
|
|
187
|
+
return json;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
var Decode = {
|
|
191
|
+
bool,
|
|
192
|
+
$$null,
|
|
193
|
+
string,
|
|
194
|
+
float,
|
|
195
|
+
object,
|
|
196
|
+
array
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// src/cli/FrontmanVite__Cli__Detect.res.mjs
|
|
200
|
+
async function fileExists(path) {
|
|
201
|
+
try {
|
|
202
|
+
await Fs.promises.access(path);
|
|
203
|
+
return true;
|
|
204
|
+
} catch (exn) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async function readFile(path) {
|
|
209
|
+
try {
|
|
210
|
+
return await Fs.promises.readFile(path, "utf8");
|
|
211
|
+
} catch (exn) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async function detectPackageManager(projectDir) {
|
|
216
|
+
let checkDir = async (dir) => {
|
|
217
|
+
let bunLockb = Nodepath.join(dir, "bun.lockb");
|
|
218
|
+
let bunLock = Nodepath.join(dir, "bun.lock");
|
|
219
|
+
let denoLock = Nodepath.join(dir, "deno.lock");
|
|
220
|
+
let pnpmLock = Nodepath.join(dir, "pnpm-lock.yaml");
|
|
221
|
+
let yarnLock = Nodepath.join(dir, "yarn.lock");
|
|
222
|
+
let npmLock = Nodepath.join(dir, "package-lock.json");
|
|
223
|
+
if (await fileExists(bunLockb) || await fileExists(bunLock)) {
|
|
224
|
+
return "Bun";
|
|
225
|
+
} else if (await fileExists(denoLock)) {
|
|
226
|
+
return "Deno";
|
|
227
|
+
} else if (await fileExists(pnpmLock)) {
|
|
228
|
+
return "Pnpm";
|
|
229
|
+
} else if (await fileExists(yarnLock)) {
|
|
230
|
+
return "Yarn";
|
|
231
|
+
} else if (await fileExists(npmLock)) {
|
|
232
|
+
return "Npm";
|
|
233
|
+
} else {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
let pm = await checkDir(projectDir);
|
|
238
|
+
if (pm !== void 0) {
|
|
239
|
+
return pm;
|
|
240
|
+
}
|
|
241
|
+
let parentDir = Nodepath.dirname(projectDir);
|
|
242
|
+
if (parentDir === projectDir) {
|
|
243
|
+
return "Npm";
|
|
244
|
+
}
|
|
245
|
+
let pm$1 = await checkDir(parentDir);
|
|
246
|
+
if (pm$1 !== void 0) {
|
|
247
|
+
return pm$1;
|
|
248
|
+
}
|
|
249
|
+
let grandparentDir = Nodepath.dirname(parentDir);
|
|
250
|
+
if (grandparentDir === parentDir) {
|
|
251
|
+
return "Npm";
|
|
252
|
+
}
|
|
253
|
+
let pm$2 = await checkDir(grandparentDir);
|
|
254
|
+
if (pm$2 !== void 0) {
|
|
255
|
+
return pm$2;
|
|
256
|
+
} else {
|
|
257
|
+
return "Npm";
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
var frontmanImportPattern = /@frontman-ai\/vite|frontman-vite|frontmanPlugin/;
|
|
261
|
+
async function findViteConfig(projectDir) {
|
|
262
|
+
let candidates = [
|
|
263
|
+
"vite.config.ts",
|
|
264
|
+
"vite.config.js",
|
|
265
|
+
"vite.config.mts",
|
|
266
|
+
"vite.config.mjs"
|
|
267
|
+
];
|
|
268
|
+
let check2 = async (remaining) => {
|
|
269
|
+
let fileName = remaining[0];
|
|
270
|
+
if (fileName === void 0) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
let filePath = Nodepath.join(projectDir, fileName);
|
|
274
|
+
let content = await readFile(filePath);
|
|
275
|
+
if (content !== void 0) {
|
|
276
|
+
return [
|
|
277
|
+
fileName,
|
|
278
|
+
content
|
|
279
|
+
];
|
|
280
|
+
}
|
|
281
|
+
let rest = remaining.slice(1, remaining.length);
|
|
282
|
+
return await check2(rest);
|
|
283
|
+
};
|
|
284
|
+
return await check2(candidates);
|
|
285
|
+
}
|
|
286
|
+
async function analyzeViteConfig(projectDir) {
|
|
287
|
+
let match = await findViteConfig(projectDir);
|
|
288
|
+
if (match === void 0) {
|
|
289
|
+
return [
|
|
290
|
+
"NotFound",
|
|
291
|
+
"vite.config.ts"
|
|
292
|
+
];
|
|
293
|
+
}
|
|
294
|
+
let content = match[1];
|
|
295
|
+
let fileName = match[0];
|
|
296
|
+
if (frontmanImportPattern.test(content)) {
|
|
297
|
+
return [
|
|
298
|
+
"HasFrontman",
|
|
299
|
+
fileName
|
|
300
|
+
];
|
|
301
|
+
}
|
|
302
|
+
let filePath = Nodepath.join(projectDir, fileName);
|
|
303
|
+
return [
|
|
304
|
+
{
|
|
305
|
+
TAG: "NeedsFrontman",
|
|
306
|
+
filePath,
|
|
307
|
+
content
|
|
308
|
+
},
|
|
309
|
+
fileName
|
|
310
|
+
];
|
|
311
|
+
}
|
|
312
|
+
async function hasPackageJson(projectDir) {
|
|
313
|
+
return await fileExists(Nodepath.join(projectDir, "package.json"));
|
|
314
|
+
}
|
|
315
|
+
async function hasViteDependency(projectDir) {
|
|
316
|
+
let pkgPath = Nodepath.join(projectDir, "package.json");
|
|
317
|
+
let content = await readFile(pkgPath);
|
|
318
|
+
if (content === void 0) {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
let json = JSON.parse(content);
|
|
323
|
+
let obj = Decode.object(json);
|
|
324
|
+
if (obj === void 0) {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
let checkDeps = (key) => mapOr(flatMap(obj[key], Decode.object), false, (deps) => isSome(deps["vite"]));
|
|
328
|
+
if (checkDeps("dependencies")) {
|
|
329
|
+
return true;
|
|
330
|
+
} else {
|
|
331
|
+
return checkDeps("devDependencies");
|
|
332
|
+
}
|
|
333
|
+
} catch (exn) {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async function detect(projectDir) {
|
|
338
|
+
let hasPackage = await hasPackageJson(projectDir);
|
|
339
|
+
if (!hasPackage) {
|
|
340
|
+
return {
|
|
341
|
+
TAG: "Error",
|
|
342
|
+
_0: "No package.json found. Please run from your Vite project root."
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
let hasVite = await hasViteDependency(projectDir);
|
|
346
|
+
if (!hasVite) {
|
|
347
|
+
return {
|
|
348
|
+
TAG: "Error",
|
|
349
|
+
_0: "Could not find vite in package.json. Please verify this is a Vite project."
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
let match = await analyzeViteConfig(projectDir);
|
|
353
|
+
let packageManager = await detectPackageManager(projectDir);
|
|
354
|
+
return {
|
|
355
|
+
TAG: "Ok",
|
|
356
|
+
_0: {
|
|
357
|
+
viteConfig: match[0],
|
|
358
|
+
packageManager,
|
|
359
|
+
viteConfigFileName: match[1]
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function getPackageManagerCommand(pm) {
|
|
364
|
+
switch (pm) {
|
|
365
|
+
case "Npm":
|
|
366
|
+
return "npm";
|
|
367
|
+
case "Yarn":
|
|
368
|
+
return "npx yarn";
|
|
369
|
+
case "Pnpm":
|
|
370
|
+
return "npx pnpm";
|
|
371
|
+
case "Bun":
|
|
372
|
+
return "bun";
|
|
373
|
+
case "Deno":
|
|
374
|
+
return "deno";
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function getDevCommand(pm) {
|
|
378
|
+
switch (pm) {
|
|
379
|
+
case "Npm":
|
|
380
|
+
return "npm run dev";
|
|
381
|
+
case "Yarn":
|
|
382
|
+
return "yarn dev";
|
|
383
|
+
case "Pnpm":
|
|
384
|
+
return "pnpm dev";
|
|
385
|
+
case "Bun":
|
|
386
|
+
return "bun dev";
|
|
387
|
+
case "Deno":
|
|
388
|
+
return "deno task dev";
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function getInstallArgs(pm) {
|
|
392
|
+
switch (pm) {
|
|
393
|
+
case "Npm":
|
|
394
|
+
return [
|
|
395
|
+
"install",
|
|
396
|
+
"-D"
|
|
397
|
+
];
|
|
398
|
+
case "Yarn":
|
|
399
|
+
return [
|
|
400
|
+
"add",
|
|
401
|
+
"-D"
|
|
402
|
+
];
|
|
403
|
+
case "Pnpm":
|
|
404
|
+
return [
|
|
405
|
+
"add",
|
|
406
|
+
"--save-dev"
|
|
407
|
+
];
|
|
408
|
+
case "Bun":
|
|
409
|
+
case "Deno":
|
|
410
|
+
return [
|
|
411
|
+
"add",
|
|
412
|
+
"--dev"
|
|
413
|
+
];
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/cli/FrontmanVite__Cli__Templates.res.mjs
|
|
418
|
+
function banner() {
|
|
419
|
+
let l1 = purpleBold(" ___ _ ");
|
|
420
|
+
let l2 = purpleBold(" | __| _ ___ _ _ | |_ _ __ __ _ _ _ ");
|
|
421
|
+
let l3 = purpleBold(" | _| '_/ _ \\ ' \\| _| ' \\/ _` | ' \\ ");
|
|
422
|
+
let l4 = purpleBold(" |_||_| \\___/_||_|\\__|_|_|_\\__,_|_||_|");
|
|
423
|
+
let tagline = purpleDim(" AI that sees your DOM and edits your frontend");
|
|
424
|
+
return `
|
|
425
|
+
` + l1 + `
|
|
426
|
+
` + l2 + `
|
|
427
|
+
` + l3 + `
|
|
428
|
+
` + l4 + `
|
|
429
|
+
|
|
430
|
+
` + tagline + `
|
|
431
|
+
`;
|
|
432
|
+
}
|
|
433
|
+
function viteConfig(fileName) {
|
|
434
|
+
let bar = yellow("|");
|
|
435
|
+
return ` ` + bar + `
|
|
436
|
+
` + bar + ` ` + yellowBold(fileName) + ` needs manual modification.
|
|
437
|
+
` + bar + `
|
|
438
|
+
` + bar + ` ` + purple("1.") + ` Add import at the top of the file:
|
|
439
|
+
` + bar + `
|
|
440
|
+
` + bar + ` ` + dim("import { frontmanPlugin } from '@frontman-ai/vite';") + `
|
|
441
|
+
` + bar + `
|
|
442
|
+
` + bar + ` ` + purple("2.") + ` Add ` + bold("frontmanPlugin()") + ` to your plugins array:
|
|
443
|
+
` + bar + `
|
|
444
|
+
` + bar + ` ` + dim("plugins: [") + `
|
|
445
|
+
` + bar + ` ` + dim(" frontmanPlugin(),") + `
|
|
446
|
+
` + bar + ` ` + dim(" // ...your other plugins") + `
|
|
447
|
+
` + bar + ` ` + dim("],") + `
|
|
448
|
+
` + bar + `
|
|
449
|
+
` + bar + ` ` + bold("Docs:") + ` ` + dim("https://frontman.sh/docs/vite") + `
|
|
450
|
+
` + bar;
|
|
451
|
+
}
|
|
452
|
+
var ManualInstructions = {
|
|
453
|
+
viteConfig
|
|
454
|
+
};
|
|
455
|
+
function fileCreated(fileName) {
|
|
456
|
+
return ` ` + check + ` Created ` + bold(fileName);
|
|
457
|
+
}
|
|
458
|
+
function fileUpdated(fileName) {
|
|
459
|
+
return ` ` + check + ` Updated ` + bold(fileName) + ` ` + dim("(added frontmanPlugin)");
|
|
460
|
+
}
|
|
461
|
+
function fileSkipped(fileName) {
|
|
462
|
+
return ` ` + purple("\u2013") + ` Skipped ` + bold(fileName) + ` ` + dim("(already configured)");
|
|
463
|
+
}
|
|
464
|
+
function manualEditRequired(fileName) {
|
|
465
|
+
return ` ` + warn + ` ` + bold(fileName) + ` requires manual setup ` + dim("(see details below)");
|
|
466
|
+
}
|
|
467
|
+
function installComplete(devCommand, port) {
|
|
468
|
+
return `
|
|
469
|
+
` + purpleBold("Frontman setup complete!") + `
|
|
470
|
+
|
|
471
|
+
` + purpleBold("Next steps:") + `
|
|
472
|
+
` + purple("1.") + ` Start your dev server ` + dim(devCommand) + `
|
|
473
|
+
` + purple("2.") + ` Open your browser to ` + dim(`http://localhost:` + port + `/frontman`) + `
|
|
474
|
+
|
|
475
|
+
` + purple("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510") + `
|
|
476
|
+
` + purple("\u2502") + ` ` + purple("\u2502") + `
|
|
477
|
+
` + purple("\u2502") + ` Questions? Comments? Need support? ` + purple("\u2502") + `
|
|
478
|
+
` + purple("\u2502") + ` ` + purple("\u2502") + `
|
|
479
|
+
` + purple("\u2502") + ` Join us on Discord: ` + purple("\u2502") + `
|
|
480
|
+
` + purple("\u2502") + ` ` + purpleDim("https://discord.gg/J77jBzMM") + ` ` + purple("\u2502") + `
|
|
481
|
+
` + purple("\u2502") + ` ` + purple("\u2502") + `
|
|
482
|
+
` + purple("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518") + `
|
|
483
|
+
`;
|
|
484
|
+
}
|
|
485
|
+
var dryRunHeader = ` ` + warn + ` ` + yellowBold("DRY RUN MODE") + ` ` + dim("\u2014 No files will be created") + `
|
|
486
|
+
`;
|
|
487
|
+
var SuccessMessages = {
|
|
488
|
+
fileCreated,
|
|
489
|
+
fileUpdated,
|
|
490
|
+
fileSkipped,
|
|
491
|
+
manualEditRequired,
|
|
492
|
+
installComplete,
|
|
493
|
+
dryRunHeader
|
|
494
|
+
};
|
|
495
|
+
var importLine = `import { frontmanPlugin } from '@frontman-ai/vite';`;
|
|
496
|
+
|
|
497
|
+
// src/cli/FrontmanVite__Cli__Install.res.mjs
|
|
498
|
+
async function installDependencies(projectDir, packageManager, dryRun) {
|
|
499
|
+
let pm = getPackageManagerCommand(packageManager);
|
|
500
|
+
let args = getInstallArgs(packageManager);
|
|
501
|
+
let packages = ["@frontman-ai/vite"];
|
|
502
|
+
let packages$1;
|
|
503
|
+
packages$1 = packageManager === "Deno" ? packages.map((p) => "npm:" + p) : packages;
|
|
504
|
+
let cmd = pm + ` ` + args.join(" ") + ` ` + packages$1.join(" ");
|
|
505
|
+
if (dryRun) {
|
|
506
|
+
console.log(` ` + dim(`Would run: ` + cmd));
|
|
507
|
+
return {
|
|
508
|
+
TAG: "Ok",
|
|
509
|
+
_0: void 0
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
console.log(` ` + purple("Installing dependencies with " + pm + "..."));
|
|
513
|
+
let err = await execWithOptions(cmd, {
|
|
514
|
+
cwd: projectDir
|
|
515
|
+
});
|
|
516
|
+
if (err.TAG === "Ok") {
|
|
517
|
+
console.log(` ` + check + ` Dependencies installed`);
|
|
518
|
+
return {
|
|
519
|
+
TAG: "Ok",
|
|
520
|
+
_0: void 0
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
let err$1 = err._0;
|
|
524
|
+
let stderr = err$1.stderr === "" ? "Unknown error" : err$1.stderr;
|
|
525
|
+
return {
|
|
526
|
+
TAG: "Error",
|
|
527
|
+
_0: `Failed to install dependencies: ` + stderr
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function injectFrontmanPlugin(content) {
|
|
531
|
+
let pluginsPattern = /plugins\s*:\s*\[/;
|
|
532
|
+
if (!pluginsPattern.test(content)) {
|
|
533
|
+
return {
|
|
534
|
+
TAG: "Error",
|
|
535
|
+
_0: "Could not find a `plugins: [` array in your Vite config"
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
let importStatement = importLine + "\n";
|
|
539
|
+
let lines = content.split("\n");
|
|
540
|
+
let lastImportIdx = {
|
|
541
|
+
contents: -1
|
|
542
|
+
};
|
|
543
|
+
lines.forEach((line, idx) => {
|
|
544
|
+
let trimmed = line.trim();
|
|
545
|
+
if (trimmed.startsWith("import ") || trimmed.startsWith("import{")) {
|
|
546
|
+
lastImportIdx.contents = idx;
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
let contentWithImport;
|
|
551
|
+
if (lastImportIdx.contents >= 0) {
|
|
552
|
+
let before = lines.slice(0, lastImportIdx.contents + 1 | 0).join("\n");
|
|
553
|
+
let after = lines.slice(lastImportIdx.contents + 1 | 0, lines.length).join("\n");
|
|
554
|
+
contentWithImport = before + "\n" + importStatement + after;
|
|
555
|
+
} else {
|
|
556
|
+
contentWithImport = importStatement + "\n" + content;
|
|
557
|
+
}
|
|
558
|
+
let result = contentWithImport.replace(/plugins\s*:\s*\[/, "plugins: [\n frontmanPlugin(),");
|
|
559
|
+
return {
|
|
560
|
+
TAG: "Ok",
|
|
561
|
+
_0: result
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
async function handleViteConfig(projectDir, info, dryRun) {
|
|
565
|
+
let match = info.viteConfig;
|
|
566
|
+
if (typeof match !== "object") {
|
|
567
|
+
if (match === "NotFound") {
|
|
568
|
+
let fileName = "vite.config.ts";
|
|
569
|
+
let filePath = Nodepath.join(projectDir, fileName);
|
|
570
|
+
if (dryRun) {
|
|
571
|
+
console.log(` ` + dim(`Would create: ` + fileName));
|
|
572
|
+
return {
|
|
573
|
+
TAG: "Ok",
|
|
574
|
+
_0: void 0
|
|
575
|
+
};
|
|
576
|
+
} else {
|
|
577
|
+
await Fs.promises.writeFile(filePath, `import { defineConfig } from 'vite';
|
|
578
|
+
import { frontmanPlugin } from '@frontman-ai/vite';
|
|
579
|
+
|
|
580
|
+
export default defineConfig({
|
|
581
|
+
plugins: [
|
|
582
|
+
frontmanPlugin(),
|
|
583
|
+
],
|
|
584
|
+
});
|
|
585
|
+
`, "utf8");
|
|
586
|
+
console.log(SuccessMessages.fileCreated(fileName));
|
|
587
|
+
return {
|
|
588
|
+
TAG: "Ok",
|
|
589
|
+
_0: void 0
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
console.log(SuccessMessages.fileSkipped(info.viteConfigFileName));
|
|
594
|
+
return {
|
|
595
|
+
TAG: "Ok",
|
|
596
|
+
_0: void 0
|
|
597
|
+
};
|
|
598
|
+
} else {
|
|
599
|
+
if (dryRun) {
|
|
600
|
+
console.log(` ` + dim(`Would modify: ` + info.viteConfigFileName));
|
|
601
|
+
return {
|
|
602
|
+
TAG: "Ok",
|
|
603
|
+
_0: void 0
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
let newContent = injectFrontmanPlugin(match.content);
|
|
607
|
+
if (newContent.TAG === "Ok") {
|
|
608
|
+
await Fs.promises.writeFile(match.filePath, newContent._0, "utf8");
|
|
609
|
+
console.log(SuccessMessages.fileUpdated(info.viteConfigFileName));
|
|
610
|
+
return {
|
|
611
|
+
TAG: "Ok",
|
|
612
|
+
_0: void 0
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
console.log(SuccessMessages.manualEditRequired(info.viteConfigFileName));
|
|
616
|
+
return {
|
|
617
|
+
TAG: "Error",
|
|
618
|
+
_0: ManualInstructions.viteConfig(info.viteConfigFileName)
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
async function run(options) {
|
|
623
|
+
let projectDir = getOr(options.prefix, process.cwd());
|
|
624
|
+
console.log(banner());
|
|
625
|
+
console.log(` ` + bullet + ` ` + bold("Server:") + ` ` + options.server);
|
|
626
|
+
if (options.dryRun) {
|
|
627
|
+
console.log("");
|
|
628
|
+
console.log(SuccessMessages.dryRunHeader);
|
|
629
|
+
}
|
|
630
|
+
let msg = await detect(projectDir);
|
|
631
|
+
if (msg.TAG === "Ok") {
|
|
632
|
+
let info = msg._0;
|
|
633
|
+
console.log(` ` + bullet + ` ` + bold("Detected:") + ` Vite project`);
|
|
634
|
+
console.log("");
|
|
635
|
+
if (!options.skipDeps) {
|
|
636
|
+
let msg$1 = await installDependencies(projectDir, info.packageManager, options.dryRun);
|
|
637
|
+
if (msg$1.TAG !== "Ok") {
|
|
638
|
+
console.error(` ` + warn + ` ` + msg$1._0);
|
|
639
|
+
}
|
|
640
|
+
console.log("");
|
|
641
|
+
}
|
|
642
|
+
let manualSteps = [];
|
|
643
|
+
let details = await handleViteConfig(projectDir, info, options.dryRun);
|
|
644
|
+
if (details.TAG !== "Ok") {
|
|
645
|
+
manualSteps.push(details._0);
|
|
646
|
+
}
|
|
647
|
+
if (manualSteps.length !== 0) {
|
|
648
|
+
console.log("");
|
|
649
|
+
console.log(` ` + divider);
|
|
650
|
+
console.log("");
|
|
651
|
+
console.log(` ` + yellowBold("Manual steps required:"));
|
|
652
|
+
console.log("");
|
|
653
|
+
manualSteps.forEach((step) => {
|
|
654
|
+
console.log(step);
|
|
655
|
+
});
|
|
656
|
+
console.log("");
|
|
657
|
+
return {
|
|
658
|
+
TAG: "PartialSuccess",
|
|
659
|
+
manualStepsRequired: manualSteps
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
if (!options.dryRun) {
|
|
663
|
+
let devCommand = getDevCommand(info.packageManager);
|
|
664
|
+
console.log("");
|
|
665
|
+
console.log(` ` + divider);
|
|
666
|
+
console.log(SuccessMessages.installComplete(devCommand, "5173"));
|
|
667
|
+
}
|
|
668
|
+
return "Success";
|
|
669
|
+
}
|
|
670
|
+
let msg$2 = msg._0;
|
|
671
|
+
console.error(` ` + warn + ` ` + bold("Error:") + ` ` + msg$2);
|
|
672
|
+
return {
|
|
673
|
+
TAG: "Failure",
|
|
674
|
+
_0: msg$2
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// src/cli/FrontmanVite__Cli.res.mjs
|
|
679
|
+
var helpText = `
|
|
680
|
+
Frontman Vite CLI
|
|
681
|
+
|
|
682
|
+
Usage:
|
|
683
|
+
@frontman-ai/vite <command> [options]
|
|
684
|
+
|
|
685
|
+
Commands:
|
|
686
|
+
install Install Frontman in a Vite project
|
|
687
|
+
|
|
688
|
+
Options:
|
|
689
|
+
--server <host> Frontman server host (default: api.frontman.sh)
|
|
690
|
+
--prefix <path> Target directory (default: current directory)
|
|
691
|
+
--dry-run Preview changes without writing files
|
|
692
|
+
--skip-deps Skip dependency installation
|
|
693
|
+
--help Show this help message
|
|
694
|
+
|
|
695
|
+
Examples:
|
|
696
|
+
npx @frontman-ai/vite install
|
|
697
|
+
npx @frontman-ai/vite install --server frontman.company.com
|
|
698
|
+
npx @frontman-ai/vite install --dry-run
|
|
699
|
+
`;
|
|
700
|
+
function parseArgs(argv) {
|
|
701
|
+
let args = argv.slice(2, argv.length);
|
|
702
|
+
let _remaining = args;
|
|
703
|
+
let _result = {
|
|
704
|
+
command: void 0,
|
|
705
|
+
server: void 0,
|
|
706
|
+
prefix: void 0,
|
|
707
|
+
dryRun: false,
|
|
708
|
+
skipDeps: false,
|
|
709
|
+
help: false
|
|
710
|
+
};
|
|
711
|
+
while (true) {
|
|
712
|
+
let result = _result;
|
|
713
|
+
let remaining = _remaining;
|
|
714
|
+
let arg = remaining[0];
|
|
715
|
+
if (arg === void 0) {
|
|
716
|
+
return result;
|
|
717
|
+
}
|
|
718
|
+
let rest = remaining.slice(1, remaining.length);
|
|
719
|
+
switch (arg) {
|
|
720
|
+
case "--dry-run":
|
|
721
|
+
_result = {
|
|
722
|
+
command: result.command,
|
|
723
|
+
server: result.server,
|
|
724
|
+
prefix: result.prefix,
|
|
725
|
+
dryRun: true,
|
|
726
|
+
skipDeps: result.skipDeps,
|
|
727
|
+
help: result.help
|
|
728
|
+
};
|
|
729
|
+
_remaining = rest;
|
|
730
|
+
continue;
|
|
731
|
+
case "--prefix":
|
|
732
|
+
let value = rest[0];
|
|
733
|
+
let nextRest = rest.slice(1, rest.length);
|
|
734
|
+
_result = {
|
|
735
|
+
command: result.command,
|
|
736
|
+
server: result.server,
|
|
737
|
+
prefix: value,
|
|
738
|
+
dryRun: result.dryRun,
|
|
739
|
+
skipDeps: result.skipDeps,
|
|
740
|
+
help: result.help
|
|
741
|
+
};
|
|
742
|
+
_remaining = nextRest;
|
|
743
|
+
continue;
|
|
744
|
+
case "--server":
|
|
745
|
+
let value$1 = rest[0];
|
|
746
|
+
let nextRest$1 = rest.slice(1, rest.length);
|
|
747
|
+
_result = {
|
|
748
|
+
command: result.command,
|
|
749
|
+
server: value$1,
|
|
750
|
+
prefix: result.prefix,
|
|
751
|
+
dryRun: result.dryRun,
|
|
752
|
+
skipDeps: result.skipDeps,
|
|
753
|
+
help: result.help
|
|
754
|
+
};
|
|
755
|
+
_remaining = nextRest$1;
|
|
756
|
+
continue;
|
|
757
|
+
case "--skip-deps":
|
|
758
|
+
_result = {
|
|
759
|
+
command: result.command,
|
|
760
|
+
server: result.server,
|
|
761
|
+
prefix: result.prefix,
|
|
762
|
+
dryRun: result.dryRun,
|
|
763
|
+
skipDeps: true,
|
|
764
|
+
help: result.help
|
|
765
|
+
};
|
|
766
|
+
_remaining = rest;
|
|
767
|
+
continue;
|
|
768
|
+
case "--help":
|
|
769
|
+
case "-h":
|
|
770
|
+
break;
|
|
771
|
+
case "install":
|
|
772
|
+
_result = {
|
|
773
|
+
command: "install",
|
|
774
|
+
server: result.server,
|
|
775
|
+
prefix: result.prefix,
|
|
776
|
+
dryRun: result.dryRun,
|
|
777
|
+
skipDeps: result.skipDeps,
|
|
778
|
+
help: result.help
|
|
779
|
+
};
|
|
780
|
+
_remaining = rest;
|
|
781
|
+
continue;
|
|
782
|
+
default:
|
|
783
|
+
_remaining = rest;
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
_result = {
|
|
787
|
+
command: result.command,
|
|
788
|
+
server: result.server,
|
|
789
|
+
prefix: result.prefix,
|
|
790
|
+
dryRun: result.dryRun,
|
|
791
|
+
skipDeps: result.skipDeps,
|
|
792
|
+
help: true
|
|
793
|
+
};
|
|
794
|
+
_remaining = rest;
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
async function main() {
|
|
799
|
+
let args = parseArgs(process.argv);
|
|
800
|
+
if (args.help) {
|
|
801
|
+
console.log(helpText);
|
|
802
|
+
Process.exit(0);
|
|
803
|
+
}
|
|
804
|
+
let cmd = args.command;
|
|
805
|
+
if (cmd !== void 0) {
|
|
806
|
+
if (cmd === "install") {
|
|
807
|
+
let server = getOr(args.server, "api.frontman.sh");
|
|
808
|
+
let result = await run({
|
|
809
|
+
server,
|
|
810
|
+
prefix: args.prefix,
|
|
811
|
+
dryRun: args.dryRun,
|
|
812
|
+
skipDeps: args.skipDeps
|
|
813
|
+
});
|
|
814
|
+
if (typeof result !== "object") {
|
|
815
|
+
Process.exit(0);
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
if (result.TAG === "PartialSuccess") {
|
|
819
|
+
Process.exit(0);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
Process.exit(1);
|
|
823
|
+
return;
|
|
824
|
+
} else {
|
|
825
|
+
console.error(`Unknown command: ` + cmd);
|
|
826
|
+
console.log(helpText);
|
|
827
|
+
Process.exit(1);
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
} else {
|
|
831
|
+
console.log(helpText);
|
|
832
|
+
Process.exit(0);
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
main();
|
package/dist/index.d.ts
CHANGED
|
@@ -20,20 +20,22 @@ import * as FrontmanCore__ToolRegistry$FrontmanFrontmanCore from '@frontman/fron
|
|
|
20
20
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
let productionHost = "api.frontman.sh";
|
|
24
|
+
|
|
23
25
|
let host = process.env["FRONTMAN_HOST"];
|
|
24
26
|
|
|
25
27
|
let defaultHost = host !== undefined ? host : "frontman.local:4000";
|
|
26
28
|
|
|
27
29
|
function makeFromObject(config) {
|
|
28
|
-
let
|
|
30
|
+
let host = Stdlib_Option.getOr(config.host, defaultHost);
|
|
31
|
+
let isDev = Stdlib_Option.getOr(config.isDev, host !== productionHost);
|
|
29
32
|
let projectRoot = Stdlib_Option.getOr(Stdlib_Option.orElse(config.projectRoot, Stdlib_Option.orElse(process.env["PROJECT_ROOT"], process.env["PWD"])), ".");
|
|
30
33
|
let sourceRoot = Stdlib_Option.getOr(config.sourceRoot, projectRoot);
|
|
31
34
|
let basePath = Stdlib_Option.getOr(config.basePath, "frontman");
|
|
32
35
|
let serverName = Stdlib_Option.getOr(config.serverName, "frontman-vite");
|
|
33
36
|
let serverVersion = Stdlib_Option.getOr(config.serverVersion, "1.0.0");
|
|
34
|
-
let host = Stdlib_Option.getOr(config.host, defaultHost);
|
|
35
37
|
let isLightTheme = Stdlib_Option.getOr(config.isLightTheme, false);
|
|
36
|
-
let baseUrl = Stdlib_Option.getOr(process.env["FRONTMAN_CLIENT_URL"], isDev ? "http://localhost:5173/src/Main.res.mjs" : "https://frontman.
|
|
38
|
+
let baseUrl = Stdlib_Option.getOr(process.env["FRONTMAN_CLIENT_URL"], isDev ? "http://localhost:5173/src/Main.res.mjs" : "https://app.frontman.sh/frontman.es.js");
|
|
37
39
|
let url = new URL(baseUrl);
|
|
38
40
|
let clientUrl = Stdlib_Option.getOr(config.clientUrl, (url.searchParams.set("clientName", "vite"), url.searchParams.set("host", host), url.href));
|
|
39
41
|
let parsedUrl = new URL(clientUrl);
|
package/dist/index.js
CHANGED
|
@@ -110,18 +110,19 @@ function orElse(opt, other) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
// src/FrontmanVite__Config.res.mjs
|
|
113
|
+
var productionHost = "api.frontman.sh";
|
|
113
114
|
var host = process.env["FRONTMAN_HOST"];
|
|
114
115
|
var defaultHost = host !== void 0 ? host : "frontman.local:4000";
|
|
115
116
|
function makeFromObject(config) {
|
|
116
|
-
let
|
|
117
|
+
let host2 = getOr(config.host, defaultHost);
|
|
118
|
+
let isDev = getOr(config.isDev, host2 !== productionHost);
|
|
117
119
|
let projectRoot = getOr(orElse(config.projectRoot, orElse(process.env["PROJECT_ROOT"], process.env["PWD"])), ".");
|
|
118
120
|
let sourceRoot = getOr(config.sourceRoot, projectRoot);
|
|
119
121
|
let basePath = getOr(config.basePath, "frontman");
|
|
120
122
|
let serverName = getOr(config.serverName, "frontman-vite");
|
|
121
123
|
let serverVersion = getOr(config.serverVersion, "1.0.0");
|
|
122
|
-
let host2 = getOr(config.host, defaultHost);
|
|
123
124
|
let isLightTheme = getOr(config.isLightTheme, false);
|
|
124
|
-
let baseUrl = getOr(process.env["FRONTMAN_CLIENT_URL"], isDev ? "http://localhost:5173/src/Main.res.mjs" : "https://frontman.
|
|
125
|
+
let baseUrl = getOr(process.env["FRONTMAN_CLIENT_URL"], isDev ? "http://localhost:5173/src/Main.res.mjs" : "https://app.frontman.sh/frontman.es.js");
|
|
125
126
|
let url2 = new URL(baseUrl);
|
|
126
127
|
let clientUrl = getOr(config.clientUrl, (url2.searchParams.set("clientName", "vite"), url2.searchParams.set("host", host2), url2.href));
|
|
127
128
|
let parsedUrl = new URL(clientUrl);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.2",
|
|
7
7
|
"description": "Vite integration for Frontman - AI-powered development tools",
|
|
8
8
|
"license": "Apache-2.0",
|
|
9
9
|
"author": "Frontman AI",
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"default": "./dist/index.js"
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
|
+
"bin": {
|
|
38
|
+
"frontman-vite": "./dist/cli.js",
|
|
39
|
+
"@frontman-ai/vite": "./dist/cli.js"
|
|
40
|
+
},
|
|
37
41
|
"files": [
|
|
38
42
|
"dist",
|
|
39
43
|
"README.md"
|