@kosdev-code/kos-ui-cli 2.1.19 → 2.1.21
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kosdev-code/kos-ui-cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.21",
|
|
4
4
|
"bin": {
|
|
5
5
|
"kosui": "./src/lib/cli.mjs"
|
|
6
6
|
},
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"main": "./src/index.js",
|
|
22
22
|
"kos": {
|
|
23
23
|
"build": {
|
|
24
|
-
"gitHash": "
|
|
24
|
+
"gitHash": "ad41d22bfee8c28adb7ca01b7a9685d5b9e46f35"
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"publishConfig": {
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
// generators/dev/index.mjs
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { spawn } from "child_process";
|
|
4
|
+
import { existsSync, mkdirSync, createWriteStream } from "fs";
|
|
5
|
+
import http from "http";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import {
|
|
8
|
+
getAllHosts,
|
|
9
|
+
getHost,
|
|
10
|
+
filterPlugins,
|
|
11
|
+
checkProjectExists,
|
|
12
|
+
validateDevConfig,
|
|
13
|
+
} from "../../utils/dev-config.mjs";
|
|
14
|
+
|
|
15
|
+
export const metadata = {
|
|
16
|
+
key: "dev",
|
|
17
|
+
name: "Development Server",
|
|
18
|
+
description: "Start development servers for host applications and plugins",
|
|
19
|
+
namedArguments: {
|
|
20
|
+
host: "host",
|
|
21
|
+
plugins: "plugins",
|
|
22
|
+
disable: "disable",
|
|
23
|
+
pluginsOnly: "pluginsOnly",
|
|
24
|
+
interactive: "interactive",
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Process management
|
|
29
|
+
const processes = [];
|
|
30
|
+
const verbose = process.env.VERBOSE_PLUGIN_DEV === "true";
|
|
31
|
+
|
|
32
|
+
function cleanup() {
|
|
33
|
+
console.log(chalk.yellow("\nCleaning up..."));
|
|
34
|
+
processes.forEach((proc) => {
|
|
35
|
+
if (proc && !proc.killed) {
|
|
36
|
+
if (verbose) {
|
|
37
|
+
console.log(chalk.cyan(` Stopping process ${proc.pid}`));
|
|
38
|
+
}
|
|
39
|
+
proc.kill();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
console.log(chalk.green("Cleanup complete"));
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Register cleanup handlers
|
|
47
|
+
process.on("SIGINT", cleanup);
|
|
48
|
+
process.on("SIGTERM", cleanup);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check if a port is healthy
|
|
52
|
+
*/
|
|
53
|
+
async function checkPortHealth(port, endpoint = "/api/kos/ui/plugins/contexts") {
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const req = http.get(`http://localhost:${port}${endpoint}`, (res) => {
|
|
56
|
+
resolve(res.statusCode === 200);
|
|
57
|
+
});
|
|
58
|
+
req.on("error", () => resolve(false));
|
|
59
|
+
req.setTimeout(1000, () => {
|
|
60
|
+
req.destroy();
|
|
61
|
+
resolve(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Wait for server to be ready
|
|
68
|
+
*/
|
|
69
|
+
async function waitForServer(port, name, maxWaitSeconds = 120) {
|
|
70
|
+
console.log(chalk.yellow(`Waiting for ${name} to be ready...`));
|
|
71
|
+
|
|
72
|
+
const startTime = Date.now();
|
|
73
|
+
const maxWaitMs = maxWaitSeconds * 1000;
|
|
74
|
+
|
|
75
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
76
|
+
const isHealthy = await checkPortHealth(port);
|
|
77
|
+
if (isHealthy) {
|
|
78
|
+
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
|
79
|
+
console.log(chalk.green(`✓ ${name} ready on port ${port}! (${elapsed}s)`));
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
|
84
|
+
if (elapsed > 0 && elapsed % 5 === 0) {
|
|
85
|
+
console.log(` ... still waiting (${elapsed}s)`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log(chalk.red(`✗ Timeout waiting for ${name}`));
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Start a dev server
|
|
97
|
+
*/
|
|
98
|
+
function startDevServer(project, port, logFile, env = {}) {
|
|
99
|
+
console.log(chalk.blue(`Starting ${project} on port ${port}`));
|
|
100
|
+
|
|
101
|
+
const logStream = createWriteStream(logFile, { flags: "w" });
|
|
102
|
+
|
|
103
|
+
const proc = spawn("npx", ["nx", "run", `${project}:serve`], {
|
|
104
|
+
env: {
|
|
105
|
+
...process.env,
|
|
106
|
+
...env,
|
|
107
|
+
VERBOSE_PLUGIN_DEV: verbose ? "true" : "false",
|
|
108
|
+
},
|
|
109
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
proc.stdout.pipe(logStream);
|
|
113
|
+
proc.stderr.pipe(logStream);
|
|
114
|
+
|
|
115
|
+
proc.on("error", (err) => {
|
|
116
|
+
console.log(chalk.red(`Failed to start ${project}: ${err.message}`));
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
proc.on("exit", (code) => {
|
|
120
|
+
if (code !== 0 && code !== null) {
|
|
121
|
+
console.log(chalk.red(`${project} exited with code ${code}`));
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
processes.push(proc);
|
|
126
|
+
|
|
127
|
+
console.log(chalk.green(` ✓ PID: ${proc.pid}, Log: ${logFile}`));
|
|
128
|
+
|
|
129
|
+
return proc;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Start internal development mode (host + plugins)
|
|
134
|
+
*/
|
|
135
|
+
async function startInternalDevelopment(hostConfig, plugins, logDir) {
|
|
136
|
+
console.log(chalk.green("=================================================================="));
|
|
137
|
+
console.log(chalk.green("Internal Development Mode"));
|
|
138
|
+
console.log(chalk.green(`Host: ${hostConfig.name}`));
|
|
139
|
+
console.log(chalk.green(`Plugins: ${plugins.length}`));
|
|
140
|
+
console.log(chalk.green("=================================================================="));
|
|
141
|
+
console.log("");
|
|
142
|
+
|
|
143
|
+
// Create log directory
|
|
144
|
+
if (!existsSync(logDir)) {
|
|
145
|
+
mkdirSync(logDir, { recursive: true });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Start plugin dev servers
|
|
149
|
+
console.log(chalk.yellow("Starting plugin dev servers..."));
|
|
150
|
+
for (const plugin of plugins) {
|
|
151
|
+
const logFile = path.join(logDir, `${plugin.project}.log`);
|
|
152
|
+
startDevServer(plugin.project, plugin.port, logFile);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
console.log("");
|
|
156
|
+
console.log(chalk.yellow("Waiting for plugin dev servers to start..."));
|
|
157
|
+
await new Promise((resolve) => setTimeout(resolve, 8000));
|
|
158
|
+
|
|
159
|
+
// Verify plugin servers
|
|
160
|
+
console.log(chalk.yellow("Verifying plugin dev servers..."));
|
|
161
|
+
let allReady = true;
|
|
162
|
+
|
|
163
|
+
for (const plugin of plugins) {
|
|
164
|
+
const isReady = await checkPortHealth(plugin.port);
|
|
165
|
+
if (isReady) {
|
|
166
|
+
console.log(chalk.green(` ✓ ${plugin.project} ready on port ${plugin.port}`));
|
|
167
|
+
} else {
|
|
168
|
+
console.log(chalk.red(` ✗ ${plugin.project} NOT ready on port ${plugin.port}`));
|
|
169
|
+
allReady = false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!allReady) {
|
|
174
|
+
console.log(chalk.red(`\nSome plugin servers failed to start. Check logs in ${logDir}/`));
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Build environment variables
|
|
179
|
+
console.log("");
|
|
180
|
+
console.log(chalk.yellow("Configuring host app environment..."));
|
|
181
|
+
|
|
182
|
+
const hostEnv = {
|
|
183
|
+
USE_LOCAL_PLUGINS: "true",
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Add plugin-specific env vars
|
|
187
|
+
for (const plugin of plugins) {
|
|
188
|
+
const envVar = plugin.project.toUpperCase().replace(/-/g, "_") + "_DEV";
|
|
189
|
+
hostEnv[envVar] = "true";
|
|
190
|
+
console.log(chalk.green(` ✓ ${envVar}=true`));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Start host app
|
|
194
|
+
console.log("");
|
|
195
|
+
console.log(chalk.yellow(`Starting host app (${hostConfig.project})...`));
|
|
196
|
+
const hostLogFile = path.join(logDir, `${hostConfig.project}.log`);
|
|
197
|
+
startDevServer(hostConfig.project, hostConfig.port, hostLogFile, hostEnv);
|
|
198
|
+
console.log("");
|
|
199
|
+
|
|
200
|
+
// Wait for host app
|
|
201
|
+
const hostReady = await waitForServer(hostConfig.port, hostConfig.project);
|
|
202
|
+
|
|
203
|
+
if (!hostReady) {
|
|
204
|
+
console.log(chalk.red("Host app failed to start"));
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Print summary
|
|
209
|
+
printSummary(hostConfig, plugins, logDir);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Start third-party development mode (plugins only)
|
|
214
|
+
*/
|
|
215
|
+
async function startThirdPartyDevelopment(hostConfig, plugins, logDir) {
|
|
216
|
+
console.log(chalk.green("=================================================================="));
|
|
217
|
+
console.log(chalk.green("Third-Party Development Mode"));
|
|
218
|
+
console.log(chalk.green(`Plugin Context: ${hostConfig.pluginContext}`));
|
|
219
|
+
console.log(chalk.green(`Plugins: ${plugins.length}`));
|
|
220
|
+
console.log(chalk.green("=================================================================="));
|
|
221
|
+
console.log("");
|
|
222
|
+
|
|
223
|
+
// Create log directory
|
|
224
|
+
if (!existsSync(logDir)) {
|
|
225
|
+
mkdirSync(logDir, { recursive: true });
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Start plugin dev servers only
|
|
229
|
+
console.log(chalk.yellow("Starting plugin dev servers..."));
|
|
230
|
+
for (const plugin of plugins) {
|
|
231
|
+
const logFile = path.join(logDir, `${plugin.project}.log`);
|
|
232
|
+
startDevServer(plugin.project, plugin.port, logFile);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log("");
|
|
236
|
+
console.log(chalk.yellow("Waiting for plugin dev servers to start..."));
|
|
237
|
+
await new Promise((resolve) => setTimeout(resolve, 8000));
|
|
238
|
+
|
|
239
|
+
// Verify plugin servers
|
|
240
|
+
console.log(chalk.yellow("Verifying plugin dev servers..."));
|
|
241
|
+
let allReady = true;
|
|
242
|
+
|
|
243
|
+
for (const plugin of plugins) {
|
|
244
|
+
const isReady = await checkPortHealth(plugin.port);
|
|
245
|
+
if (isReady) {
|
|
246
|
+
console.log(chalk.green(` ✓ ${plugin.project} ready on port ${plugin.port}`));
|
|
247
|
+
} else {
|
|
248
|
+
console.log(chalk.red(` ✗ ${plugin.project} NOT ready on port ${plugin.port}`));
|
|
249
|
+
allReady = false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (!allReady) {
|
|
254
|
+
console.log(chalk.red(`\nSome plugin servers failed to start. Check logs in ${logDir}/`));
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Print third-party instructions
|
|
259
|
+
printThirdPartyInstructions(plugins, hostConfig, logDir);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Print summary for internal development
|
|
264
|
+
*/
|
|
265
|
+
function printSummary(hostConfig, plugins, logDir) {
|
|
266
|
+
console.log("");
|
|
267
|
+
console.log(chalk.green("=================================================================="));
|
|
268
|
+
console.log(chalk.green("Development Environment Ready!"));
|
|
269
|
+
console.log(chalk.green("=================================================================="));
|
|
270
|
+
console.log("");
|
|
271
|
+
console.log(chalk.blue("Plugin Dev Servers:"));
|
|
272
|
+
|
|
273
|
+
for (const plugin of plugins) {
|
|
274
|
+
console.log(` - ${plugin.project}: http://localhost:${plugin.port}`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
console.log("");
|
|
278
|
+
console.log(chalk.blue("Host App:"));
|
|
279
|
+
console.log(` - ${hostConfig.project}: http://localhost:${hostConfig.port}`);
|
|
280
|
+
console.log("");
|
|
281
|
+
console.log(chalk.blue("Logs:"));
|
|
282
|
+
console.log(` - ${logDir}/`);
|
|
283
|
+
console.log("");
|
|
284
|
+
console.log(chalk.yellow("Press Ctrl+C to stop all servers"));
|
|
285
|
+
console.log("");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Print third-party connection instructions
|
|
290
|
+
*/
|
|
291
|
+
function printThirdPartyInstructions(plugins, hostConfig, logDir) {
|
|
292
|
+
console.log("");
|
|
293
|
+
console.log(chalk.green("=================================================================="));
|
|
294
|
+
console.log(chalk.green("Plugin Dev Servers Running"));
|
|
295
|
+
console.log(chalk.green("=================================================================="));
|
|
296
|
+
console.log("");
|
|
297
|
+
console.log(chalk.blue("Plugin Dev Servers:"));
|
|
298
|
+
|
|
299
|
+
for (const plugin of plugins) {
|
|
300
|
+
console.log(` - ${plugin.project}: http://localhost:${plugin.port}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
console.log("");
|
|
304
|
+
console.log(chalk.yellow("Connection Instructions:"));
|
|
305
|
+
console.log("");
|
|
306
|
+
console.log(chalk.cyan("Connect to your deployed device using query parameters:"));
|
|
307
|
+
console.log("");
|
|
308
|
+
|
|
309
|
+
const yourIp = "<your-development-machine-ip>";
|
|
310
|
+
const deviceUrl = "<device-ip:port>";
|
|
311
|
+
const pluginServers = plugins.map((p) => `http://${yourIp}:${p.port}`).join(",");
|
|
312
|
+
|
|
313
|
+
console.log(chalk.green(` ${deviceUrl}/?pluginDevServers=${pluginServers}`));
|
|
314
|
+
console.log("");
|
|
315
|
+
console.log(chalk.yellow("Replace:"));
|
|
316
|
+
console.log(` - ${chalk.cyan("<your-development-machine-ip>")} with your machine's IP address`);
|
|
317
|
+
console.log(` - ${chalk.cyan("<device-ip:port>")} with your device's address`);
|
|
318
|
+
console.log("");
|
|
319
|
+
console.log(chalk.yellow("Example:"));
|
|
320
|
+
const examplePluginServers = plugins.map((p) => `http://localhost:${p.port}`).join(",");
|
|
321
|
+
console.log(
|
|
322
|
+
chalk.green(
|
|
323
|
+
` http://192.168.1.100:8080/?pluginDevServers=${examplePluginServers}`
|
|
324
|
+
)
|
|
325
|
+
);
|
|
326
|
+
console.log("");
|
|
327
|
+
console.log(chalk.blue("Logs:"));
|
|
328
|
+
console.log(` - ${logDir}/`);
|
|
329
|
+
console.log("");
|
|
330
|
+
console.log(chalk.yellow("Press Ctrl+C to stop all servers"));
|
|
331
|
+
console.log("");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export default async function (plop) {
|
|
335
|
+
plop.setActionType("runDev", async function (answers) {
|
|
336
|
+
// Validate configuration
|
|
337
|
+
const validation = validateDevConfig();
|
|
338
|
+
if (!validation.isValid) {
|
|
339
|
+
console.log(chalk.red("\nError: Invalid development configuration"));
|
|
340
|
+
validation.errors.forEach((err) => console.log(chalk.red(` - ${err}`)));
|
|
341
|
+
console.log("");
|
|
342
|
+
console.log(chalk.yellow("This workspace does not support metadata-driven development."));
|
|
343
|
+
console.log(chalk.yellow("Run the migration generator or create a new workspace with the latest preset."));
|
|
344
|
+
return "Failed: Invalid configuration";
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const { host, plugins: pluginsArg, disable, pluginsOnly } = answers;
|
|
348
|
+
|
|
349
|
+
// Get host configuration
|
|
350
|
+
const hostConfig = getHost(host);
|
|
351
|
+
if (!hostConfig) {
|
|
352
|
+
console.log(chalk.red(`\nError: Host '${host}' not found in .kos.json`));
|
|
353
|
+
return `Failed: Host not found`;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Parse plugin filters
|
|
357
|
+
const pluginFilter = pluginsArg ? pluginsArg.split(",") : null;
|
|
358
|
+
const disableFilter = disable ? disable.split(",") : null;
|
|
359
|
+
|
|
360
|
+
// Filter plugins
|
|
361
|
+
const plugins = filterPlugins(hostConfig.plugins, {
|
|
362
|
+
plugins: pluginFilter,
|
|
363
|
+
disable: disableFilter,
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
if (plugins.length === 0) {
|
|
367
|
+
console.log(chalk.yellow("Warning: No plugins selected"));
|
|
368
|
+
console.log("");
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Determine log directory
|
|
372
|
+
const logDir = process.env.DEV_LOG_DIR || "/tmp/kos-dev-logs";
|
|
373
|
+
|
|
374
|
+
// Determine mode
|
|
375
|
+
const hostProjectExists = checkProjectExists(hostConfig.project);
|
|
376
|
+
|
|
377
|
+
if (hostProjectExists && !pluginsOnly) {
|
|
378
|
+
// Internal Development Mode
|
|
379
|
+
await startInternalDevelopment(hostConfig, plugins, logDir);
|
|
380
|
+
} else {
|
|
381
|
+
// Third-Party Development Mode
|
|
382
|
+
if (!pluginsOnly && !hostProjectExists) {
|
|
383
|
+
console.log(chalk.yellow(`Note: Host project '${hostConfig.project}' not found in workspace.`));
|
|
384
|
+
console.log(chalk.yellow("Starting in third-party development mode (plugins only)."));
|
|
385
|
+
console.log("");
|
|
386
|
+
}
|
|
387
|
+
await startThirdPartyDevelopment(hostConfig, plugins, logDir);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Keep process running
|
|
391
|
+
await new Promise(() => {});
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// Get available hosts for prompts
|
|
395
|
+
const hosts = getAllHosts();
|
|
396
|
+
|
|
397
|
+
if (hosts.length === 0) {
|
|
398
|
+
console.warn("[kos-cli] No hosts found in .kos.json development configuration");
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
plop.setGenerator("dev", {
|
|
402
|
+
description: "Start development servers for host applications and plugins",
|
|
403
|
+
prompts: [
|
|
404
|
+
{
|
|
405
|
+
type: "list",
|
|
406
|
+
name: "host",
|
|
407
|
+
message: "Select a host application:",
|
|
408
|
+
choices: hosts.map((h) => ({
|
|
409
|
+
name: `${h.name} (${h.type}) - ${h.plugins.length} plugin(s)`,
|
|
410
|
+
value: h.name,
|
|
411
|
+
})),
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
type: "input",
|
|
415
|
+
name: "plugins",
|
|
416
|
+
message: "Specific plugins to start (comma-separated aliases, leave empty for all enabled):",
|
|
417
|
+
default: "",
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
type: "input",
|
|
421
|
+
name: "disable",
|
|
422
|
+
message: "Plugins to disable (comma-separated aliases, leave empty for none):",
|
|
423
|
+
default: "",
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
type: "confirm",
|
|
427
|
+
name: "pluginsOnly",
|
|
428
|
+
message: "Start plugins only (third-party mode)?",
|
|
429
|
+
default: false,
|
|
430
|
+
},
|
|
431
|
+
],
|
|
432
|
+
actions: () => [{ type: "runDev" }],
|
|
433
|
+
});
|
|
434
|
+
}
|
|
@@ -23,12 +23,31 @@
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
|
+
{
|
|
27
|
+
"category": "dev",
|
|
28
|
+
"file": "index.mjs",
|
|
29
|
+
"metadata": {
|
|
30
|
+
"key": "dev",
|
|
31
|
+
"name": "Development Server",
|
|
32
|
+
"description": "Start development servers for host applications and plugins",
|
|
33
|
+
"namedArguments": {
|
|
34
|
+
"host": "host",
|
|
35
|
+
"plugins": "plugins",
|
|
36
|
+
"disable": "disable",
|
|
37
|
+
"pluginsOnly": "pluginsOnly",
|
|
38
|
+
"interactive": "interactive"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
26
42
|
{
|
|
27
43
|
"category": "env",
|
|
28
44
|
"file": "index.mjs",
|
|
29
45
|
"metadata": {
|
|
30
46
|
"key": "env",
|
|
31
|
-
"name": "Discover and Set Studio Environment Variables"
|
|
47
|
+
"name": "Discover and Set Studio Environment Variables",
|
|
48
|
+
"namedArguments": {
|
|
49
|
+
"interactive": "interactive"
|
|
50
|
+
}
|
|
32
51
|
}
|
|
33
52
|
},
|
|
34
53
|
{
|
|
@@ -44,6 +63,18 @@
|
|
|
44
63
|
}
|
|
45
64
|
}
|
|
46
65
|
},
|
|
66
|
+
{
|
|
67
|
+
"category": "kab",
|
|
68
|
+
"file": "index.mjs",
|
|
69
|
+
"metadata": {
|
|
70
|
+
"key": "kab",
|
|
71
|
+
"name": "Run Kab Target",
|
|
72
|
+
"namedArguments": {
|
|
73
|
+
"project": "project",
|
|
74
|
+
"interactive": "interactive"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
47
78
|
{
|
|
48
79
|
"category": "model",
|
|
49
80
|
"file": "add-future.mjs",
|
|
@@ -79,6 +110,7 @@
|
|
|
79
110
|
"parentAware": "parentAware",
|
|
80
111
|
"singleton": "singleton",
|
|
81
112
|
"dataServices": "dataServices",
|
|
113
|
+
"autoRegister": "autoRegister",
|
|
82
114
|
"dryRun": "dryRun",
|
|
83
115
|
"interactive": "interactive"
|
|
84
116
|
}
|
|
@@ -97,6 +129,7 @@
|
|
|
97
129
|
"parentAware": "parentAware",
|
|
98
130
|
"singleton": "singleton",
|
|
99
131
|
"dataServices": "dataServices",
|
|
132
|
+
"autoRegister": "autoRegister",
|
|
100
133
|
"dryRun": "dryRun",
|
|
101
134
|
"interactive": "interactive"
|
|
102
135
|
}
|
|
@@ -145,6 +178,7 @@
|
|
|
145
178
|
"singleton": "singleton",
|
|
146
179
|
"dataServices": "dataServices",
|
|
147
180
|
"futureAware": "futureAware",
|
|
181
|
+
"autoRegister": "autoRegister",
|
|
148
182
|
"dryRun": "dryRun",
|
|
149
183
|
"interactive": "interactive"
|
|
150
184
|
}
|
|
@@ -225,6 +259,17 @@
|
|
|
225
259
|
"project": "componentProject",
|
|
226
260
|
"componentProject": "componentProject"
|
|
227
261
|
}
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"key": "plugin:custom",
|
|
265
|
+
"name": "KOS UI Plugin Custom (User-Specified Contribution)",
|
|
266
|
+
"namedArguments": {
|
|
267
|
+
"name": "componentName",
|
|
268
|
+
"componentName": "componentName",
|
|
269
|
+
"project": "componentProject",
|
|
270
|
+
"componentProject": "componentProject",
|
|
271
|
+
"contributionKey": "contributionKey"
|
|
272
|
+
}
|
|
228
273
|
}
|
|
229
274
|
]
|
|
230
275
|
},
|
|
@@ -300,6 +345,29 @@
|
|
|
300
345
|
}
|
|
301
346
|
}
|
|
302
347
|
},
|
|
348
|
+
{
|
|
349
|
+
"category": "serve",
|
|
350
|
+
"file": "index.mjs",
|
|
351
|
+
"metadata": {
|
|
352
|
+
"key": "serve",
|
|
353
|
+
"name": "Run Serve Target",
|
|
354
|
+
"namedArguments": {
|
|
355
|
+
"project": "project",
|
|
356
|
+
"interactive": "interactive"
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"category": "version",
|
|
362
|
+
"file": "index.mjs",
|
|
363
|
+
"metadata": {
|
|
364
|
+
"key": "version",
|
|
365
|
+
"name": "Display CLI and SDK Version Information",
|
|
366
|
+
"namedArguments": {
|
|
367
|
+
"interactive": "interactive"
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
},
|
|
303
371
|
{
|
|
304
372
|
"category": "workspace",
|
|
305
373
|
"file": "index.mjs",
|
|
@@ -308,7 +376,8 @@
|
|
|
308
376
|
"name": "Create a new KOS UI Workspace",
|
|
309
377
|
"namedArguments": {
|
|
310
378
|
"name": "workspaceName",
|
|
311
|
-
"workspaceName": "workspaceName"
|
|
379
|
+
"workspaceName": "workspaceName",
|
|
380
|
+
"enablePlugins": "enablePlugins"
|
|
312
381
|
}
|
|
313
382
|
}
|
|
314
383
|
},
|
|
@@ -9,7 +9,8 @@ export const metadata = {
|
|
|
9
9
|
name: "Create a new KOS UI Workspace",
|
|
10
10
|
namedArguments: {
|
|
11
11
|
name: "workspaceName",
|
|
12
|
-
workspaceName: "workspaceName"
|
|
12
|
+
workspaceName: "workspaceName",
|
|
13
|
+
enablePlugins: "enablePlugins"
|
|
13
14
|
}
|
|
14
15
|
};
|
|
15
16
|
export default async function (plop) {
|
|
@@ -17,6 +18,7 @@ export default async function (plop) {
|
|
|
17
18
|
await createWorkspace("@kosdev-code/kos-nx-plugin", {
|
|
18
19
|
nxCloud: "skip",
|
|
19
20
|
name: answers.workspaceName,
|
|
21
|
+
enablePlugins: answers.enablePlugins,
|
|
20
22
|
});
|
|
21
23
|
return `Workspace ${answers.workspaceName} created.`;
|
|
22
24
|
});
|
|
@@ -30,10 +32,16 @@ export default async function (plop) {
|
|
|
30
32
|
message: "Enter the workspace name",
|
|
31
33
|
validate: required,
|
|
32
34
|
},
|
|
35
|
+
{
|
|
36
|
+
type: "confirm",
|
|
37
|
+
name: "enablePlugins",
|
|
38
|
+
message: "Do you want to enable plugin support?",
|
|
39
|
+
default: true,
|
|
40
|
+
},
|
|
33
41
|
],
|
|
34
42
|
actions: () => [{ type: "createWorkspace" }],
|
|
35
43
|
});
|
|
36
|
-
|
|
44
|
+
|
|
37
45
|
// Register additional workspace generators
|
|
38
46
|
await registerListModels(plop);
|
|
39
47
|
await registerListProjects(plop);
|
package/src/lib/plopfile.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import registerComponent from "./generators/component/index.mjs";
|
|
|
13
13
|
import registerPluginComponent from "./generators/plugin/index.mjs";
|
|
14
14
|
|
|
15
15
|
import registerCacheGenerators from "./generators/cache/index.mjs";
|
|
16
|
+
import registerDev from "./generators/dev/index.mjs";
|
|
16
17
|
import registerEnv from "./generators/env/index.mjs";
|
|
17
18
|
import registerKab from "./generators/kab/index.mjs";
|
|
18
19
|
import registerServe from "./generators/serve/index.mjs";
|
|
@@ -59,6 +60,7 @@ export default async function (plop) {
|
|
|
59
60
|
await registerSplashProject(plop);
|
|
60
61
|
await registerI18n(plop);
|
|
61
62
|
await registerI18nNamespace(plop);
|
|
63
|
+
await registerDev(plop);
|
|
62
64
|
await registerEnv(plop);
|
|
63
65
|
await registerKab(plop);
|
|
64
66
|
await registerServe(plop);
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// utils/dev-config.mjs
|
|
2
|
+
import { existsSync, readFileSync } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Read the development configuration from root .kos.json
|
|
7
|
+
*
|
|
8
|
+
* @returns {Object|null} Development config or null if not found
|
|
9
|
+
*/
|
|
10
|
+
export function getDevConfig() {
|
|
11
|
+
const workspaceRoot = process.cwd();
|
|
12
|
+
const kosJsonPath = path.join(workspaceRoot, '.kos.json');
|
|
13
|
+
|
|
14
|
+
if (!existsSync(kosJsonPath)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const content = readFileSync(kosJsonPath, 'utf-8');
|
|
20
|
+
const config = JSON.parse(content);
|
|
21
|
+
|
|
22
|
+
if (config.type !== 'root') {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!config.development || !config.development.hosts) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return config.development;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error(`[kos-cli] Error reading .kos.json: ${error.message}`);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Find a host configuration by name
|
|
39
|
+
*
|
|
40
|
+
* @param {string} hostName - Name of the host to find
|
|
41
|
+
* @returns {Object|null} Host config or null if not found
|
|
42
|
+
*/
|
|
43
|
+
export function getHost(hostName) {
|
|
44
|
+
const devConfig = getDevConfig();
|
|
45
|
+
|
|
46
|
+
if (!devConfig) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return devConfig.hosts.find(h => h.name === hostName) || null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Get all available hosts
|
|
55
|
+
*
|
|
56
|
+
* @returns {Array} Array of host configurations
|
|
57
|
+
*/
|
|
58
|
+
export function getAllHosts() {
|
|
59
|
+
const devConfig = getDevConfig();
|
|
60
|
+
|
|
61
|
+
if (!devConfig) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return devConfig.hosts || [];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Filter plugins based on options
|
|
70
|
+
*
|
|
71
|
+
* @param {Array} hostPlugins - Array of plugin configs from host
|
|
72
|
+
* @param {Object} options - Filter options
|
|
73
|
+
* @param {Array} options.plugins - Specific plugin aliases to include
|
|
74
|
+
* @param {Array} options.disable - Plugin aliases to exclude
|
|
75
|
+
* @returns {Array} Filtered array of plugin configurations
|
|
76
|
+
*/
|
|
77
|
+
export function filterPlugins(hostPlugins, options = {}) {
|
|
78
|
+
let plugins = hostPlugins.filter(p => p.enabled);
|
|
79
|
+
|
|
80
|
+
// If specific plugins requested, override enabled flag
|
|
81
|
+
if (options.plugins && options.plugins.length > 0) {
|
|
82
|
+
plugins = hostPlugins.filter(p => options.plugins.includes(p.alias));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Apply disable list
|
|
86
|
+
if (options.disable && options.disable.length > 0) {
|
|
87
|
+
plugins = plugins.filter(p => !options.disable.includes(p.alias));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return plugins;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Check if a project exists in the workspace
|
|
95
|
+
*
|
|
96
|
+
* @param {string} projectName - Name of the project
|
|
97
|
+
* @returns {boolean} True if project exists
|
|
98
|
+
*/
|
|
99
|
+
export function checkProjectExists(projectName) {
|
|
100
|
+
const workspaceRoot = process.cwd();
|
|
101
|
+
|
|
102
|
+
// Check common project locations
|
|
103
|
+
const appPath = path.join(workspaceRoot, 'apps', projectName, 'project.json');
|
|
104
|
+
const libPath = path.join(workspaceRoot, 'libs', projectName, 'project.json');
|
|
105
|
+
const pluginPath = path.join(workspaceRoot, 'plugins', projectName, 'project.json');
|
|
106
|
+
const packagesPath = path.join(workspaceRoot, 'packages', projectName, 'project.json');
|
|
107
|
+
|
|
108
|
+
return existsSync(appPath) ||
|
|
109
|
+
existsSync(libPath) ||
|
|
110
|
+
existsSync(pluginPath) ||
|
|
111
|
+
existsSync(packagesPath);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Validate development configuration
|
|
116
|
+
*
|
|
117
|
+
* @returns {Object} Validation result with isValid and errors
|
|
118
|
+
*/
|
|
119
|
+
export function validateDevConfig() {
|
|
120
|
+
const devConfig = getDevConfig();
|
|
121
|
+
const errors = [];
|
|
122
|
+
|
|
123
|
+
if (!devConfig) {
|
|
124
|
+
errors.push('.kos.json missing or does not contain development configuration');
|
|
125
|
+
return { isValid: false, errors };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!Array.isArray(devConfig.hosts) || devConfig.hosts.length === 0) {
|
|
129
|
+
errors.push('No hosts defined in development configuration');
|
|
130
|
+
return { isValid: false, errors };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Validate each host
|
|
134
|
+
devConfig.hosts.forEach((host, idx) => {
|
|
135
|
+
if (!host.name) {
|
|
136
|
+
errors.push(`Host at index ${idx} missing required 'name' field`);
|
|
137
|
+
}
|
|
138
|
+
if (!host.project) {
|
|
139
|
+
errors.push(`Host at index ${idx} missing required 'project' field`);
|
|
140
|
+
}
|
|
141
|
+
if (!host.port) {
|
|
142
|
+
errors.push(`Host at index ${idx} missing required 'port' field`);
|
|
143
|
+
}
|
|
144
|
+
if (!Array.isArray(host.plugins)) {
|
|
145
|
+
errors.push(`Host '${host.name}' missing 'plugins' array`);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return { isValid: errors.length === 0, errors };
|
|
150
|
+
}
|