@kosdev-code/kos-ui-cli 2.0.43 → 2.0.45

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.
@@ -0,0 +1,437 @@
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, endpoint = "/api/kos/ui/plugins/contexts") {
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, endpoint);
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 pluginEndpoint = plugin.healthCheckEndpoint || "/api/kos/ui/plugins/contexts";
165
+ const isReady = await checkPortHealth(plugin.port, pluginEndpoint);
166
+ if (isReady) {
167
+ console.log(chalk.green(` ✓ ${plugin.project} ready on port ${plugin.port}`));
168
+ } else {
169
+ console.log(chalk.red(` ✗ ${plugin.project} NOT ready on port ${plugin.port}`));
170
+ allReady = false;
171
+ }
172
+ }
173
+
174
+ if (!allReady) {
175
+ console.log(chalk.red(`\nSome plugin servers failed to start. Check logs in ${logDir}/`));
176
+ process.exit(1);
177
+ }
178
+
179
+ // Build environment variables
180
+ console.log("");
181
+ console.log(chalk.yellow("Configuring host app environment..."));
182
+
183
+ const hostEnv = {
184
+ USE_LOCAL_PLUGINS: "true",
185
+ };
186
+
187
+ // Add plugin-specific env vars
188
+ for (const plugin of plugins) {
189
+ const envVar = plugin.project.toUpperCase().replace(/-/g, "_") + "_DEV";
190
+ hostEnv[envVar] = "true";
191
+ console.log(chalk.green(` ✓ ${envVar}=true`));
192
+ }
193
+
194
+ // Start host app
195
+ console.log("");
196
+ console.log(chalk.yellow(`Starting host app (${hostConfig.project})...`));
197
+ const hostLogFile = path.join(logDir, `${hostConfig.project}.log`);
198
+ startDevServer(hostConfig.project, hostConfig.port, hostLogFile, hostEnv);
199
+ console.log("");
200
+
201
+ // Wait for host app
202
+ const hostEndpoint = hostConfig.healthCheckEndpoint || "/api/kos/ui/plugins/contexts";
203
+ const hostReady = await waitForServer(hostConfig.port, hostConfig.project, 120, hostEndpoint);
204
+
205
+ if (!hostReady) {
206
+ console.log(chalk.red("Host app failed to start"));
207
+ process.exit(1);
208
+ }
209
+
210
+ // Print summary
211
+ printSummary(hostConfig, plugins, logDir);
212
+ }
213
+
214
+ /**
215
+ * Start third-party development mode (plugins only)
216
+ */
217
+ async function startThirdPartyDevelopment(hostConfig, plugins, logDir) {
218
+ console.log(chalk.green("=================================================================="));
219
+ console.log(chalk.green("Third-Party Development Mode"));
220
+ console.log(chalk.green(`Plugin Context: ${hostConfig.pluginContext}`));
221
+ console.log(chalk.green(`Plugins: ${plugins.length}`));
222
+ console.log(chalk.green("=================================================================="));
223
+ console.log("");
224
+
225
+ // Create log directory
226
+ if (!existsSync(logDir)) {
227
+ mkdirSync(logDir, { recursive: true });
228
+ }
229
+
230
+ // Start plugin dev servers only
231
+ console.log(chalk.yellow("Starting plugin dev servers..."));
232
+ for (const plugin of plugins) {
233
+ const logFile = path.join(logDir, `${plugin.project}.log`);
234
+ startDevServer(plugin.project, plugin.port, logFile);
235
+ }
236
+
237
+ console.log("");
238
+ console.log(chalk.yellow("Waiting for plugin dev servers to start..."));
239
+ await new Promise((resolve) => setTimeout(resolve, 8000));
240
+
241
+ // Verify plugin servers
242
+ console.log(chalk.yellow("Verifying plugin dev servers..."));
243
+ let allReady = true;
244
+
245
+ for (const plugin of plugins) {
246
+ const pluginEndpoint = plugin.healthCheckEndpoint || "/api/kos/ui/plugins/contexts";
247
+ const isReady = await checkPortHealth(plugin.port, pluginEndpoint);
248
+ if (isReady) {
249
+ console.log(chalk.green(` ✓ ${plugin.project} ready on port ${plugin.port}`));
250
+ } else {
251
+ console.log(chalk.red(` ✗ ${plugin.project} NOT ready on port ${plugin.port}`));
252
+ allReady = false;
253
+ }
254
+ }
255
+
256
+ if (!allReady) {
257
+ console.log(chalk.red(`\nSome plugin servers failed to start. Check logs in ${logDir}/`));
258
+ process.exit(1);
259
+ }
260
+
261
+ // Print third-party instructions
262
+ printThirdPartyInstructions(plugins, hostConfig, logDir);
263
+ }
264
+
265
+ /**
266
+ * Print summary for internal development
267
+ */
268
+ function printSummary(hostConfig, plugins, logDir) {
269
+ console.log("");
270
+ console.log(chalk.green("=================================================================="));
271
+ console.log(chalk.green("Development Environment Ready!"));
272
+ console.log(chalk.green("=================================================================="));
273
+ console.log("");
274
+ console.log(chalk.blue("Plugin Dev Servers:"));
275
+
276
+ for (const plugin of plugins) {
277
+ console.log(` - ${plugin.project}: http://localhost:${plugin.port}`);
278
+ }
279
+
280
+ console.log("");
281
+ console.log(chalk.blue("Host App:"));
282
+ console.log(` - ${hostConfig.project}: http://localhost:${hostConfig.port}`);
283
+ console.log("");
284
+ console.log(chalk.blue("Logs:"));
285
+ console.log(` - ${logDir}/`);
286
+ console.log("");
287
+ console.log(chalk.yellow("Press Ctrl+C to stop all servers"));
288
+ console.log("");
289
+ }
290
+
291
+ /**
292
+ * Print third-party connection instructions
293
+ */
294
+ function printThirdPartyInstructions(plugins, hostConfig, logDir) {
295
+ console.log("");
296
+ console.log(chalk.green("=================================================================="));
297
+ console.log(chalk.green("Plugin Dev Servers Running"));
298
+ console.log(chalk.green("=================================================================="));
299
+ console.log("");
300
+ console.log(chalk.blue("Plugin Dev Servers:"));
301
+
302
+ for (const plugin of plugins) {
303
+ console.log(` - ${plugin.project}: http://localhost:${plugin.port}`);
304
+ }
305
+
306
+ console.log("");
307
+ console.log(chalk.yellow("Connection Instructions:"));
308
+ console.log("");
309
+ console.log(chalk.cyan("Connect to your deployed device using query parameters:"));
310
+ console.log("");
311
+
312
+ const yourIp = "<your-development-machine-ip>";
313
+ const deviceUrl = "<device-ip:port>";
314
+ const pluginServers = plugins.map((p) => `http://${yourIp}:${p.port}`).join(",");
315
+
316
+ console.log(chalk.green(` ${deviceUrl}/?pluginDevServers=${pluginServers}`));
317
+ console.log("");
318
+ console.log(chalk.yellow("Replace:"));
319
+ console.log(` - ${chalk.cyan("<your-development-machine-ip>")} with your machine's IP address`);
320
+ console.log(` - ${chalk.cyan("<device-ip:port>")} with your device's address`);
321
+ console.log("");
322
+ console.log(chalk.yellow("Example:"));
323
+ const examplePluginServers = plugins.map((p) => `http://localhost:${p.port}`).join(",");
324
+ console.log(
325
+ chalk.green(
326
+ ` http://192.168.1.100:8080/?pluginDevServers=${examplePluginServers}`
327
+ )
328
+ );
329
+ console.log("");
330
+ console.log(chalk.blue("Logs:"));
331
+ console.log(` - ${logDir}/`);
332
+ console.log("");
333
+ console.log(chalk.yellow("Press Ctrl+C to stop all servers"));
334
+ console.log("");
335
+ }
336
+
337
+ export default async function (plop) {
338
+ plop.setActionType("runDev", async function (answers) {
339
+ // Validate configuration
340
+ const validation = validateDevConfig();
341
+ if (!validation.isValid) {
342
+ console.log(chalk.red("\nError: Invalid development configuration"));
343
+ validation.errors.forEach((err) => console.log(chalk.red(` - ${err}`)));
344
+ console.log("");
345
+ console.log(chalk.yellow("This workspace does not support metadata-driven development."));
346
+ console.log(chalk.yellow("Run the migration generator or create a new workspace with the latest preset."));
347
+ return "Failed: Invalid configuration";
348
+ }
349
+
350
+ const { host, plugins: pluginsArg, disable, pluginsOnly } = answers;
351
+
352
+ // Get host configuration
353
+ const hostConfig = getHost(host);
354
+ if (!hostConfig) {
355
+ console.log(chalk.red(`\nError: Host '${host}' not found in .kos.json`));
356
+ return `Failed: Host not found`;
357
+ }
358
+
359
+ // Parse plugin filters
360
+ const pluginFilter = pluginsArg ? pluginsArg.split(",") : null;
361
+ const disableFilter = disable ? disable.split(",") : null;
362
+
363
+ // Filter plugins
364
+ const plugins = filterPlugins(hostConfig.plugins, {
365
+ plugins: pluginFilter,
366
+ disable: disableFilter,
367
+ });
368
+
369
+ if (plugins.length === 0) {
370
+ console.log(chalk.yellow("Warning: No plugins selected"));
371
+ console.log("");
372
+ }
373
+
374
+ // Determine log directory
375
+ const logDir = process.env.DEV_LOG_DIR || "/tmp/kos-dev-logs";
376
+
377
+ // Determine mode
378
+ const hostProjectExists = checkProjectExists(hostConfig.project);
379
+
380
+ if (hostProjectExists && !pluginsOnly) {
381
+ // Internal Development Mode
382
+ await startInternalDevelopment(hostConfig, plugins, logDir);
383
+ } else {
384
+ // Third-Party Development Mode
385
+ if (!pluginsOnly && !hostProjectExists) {
386
+ console.log(chalk.yellow(`Note: Host project '${hostConfig.project}' not found in workspace.`));
387
+ console.log(chalk.yellow("Starting in third-party development mode (plugins only)."));
388
+ console.log("");
389
+ }
390
+ await startThirdPartyDevelopment(hostConfig, plugins, logDir);
391
+ }
392
+
393
+ // Keep process running
394
+ await new Promise(() => {});
395
+ });
396
+
397
+ // Get available hosts for prompts
398
+ const hosts = getAllHosts();
399
+
400
+ if (hosts.length === 0) {
401
+ console.warn("[kos-cli] No hosts found in .kos.json development configuration");
402
+ }
403
+
404
+ plop.setGenerator("dev", {
405
+ description: "Start development servers for host applications and plugins",
406
+ prompts: [
407
+ {
408
+ type: "list",
409
+ name: "host",
410
+ message: "Select a host application:",
411
+ choices: hosts.map((h) => ({
412
+ name: `${h.name} (${h.type}) - ${h.plugins.length} plugin(s)`,
413
+ value: h.name,
414
+ })),
415
+ },
416
+ {
417
+ type: "input",
418
+ name: "plugins",
419
+ message: "Specific plugins to start (comma-separated aliases, leave empty for all enabled):",
420
+ default: "",
421
+ },
422
+ {
423
+ type: "input",
424
+ name: "disable",
425
+ message: "Plugins to disable (comma-separated aliases, leave empty for none):",
426
+ default: "",
427
+ },
428
+ {
429
+ type: "confirm",
430
+ name: "pluginsOnly",
431
+ message: "Start plugins only (third-party mode)?",
432
+ default: false,
433
+ },
434
+ ],
435
+ actions: () => [{ type: "runDev" }],
436
+ });
437
+ }
@@ -8,6 +8,7 @@ import { findStudioHome } from "../../utils/studio-home.mjs";
8
8
  export const metadata = {
9
9
  key: "env",
10
10
  name: "Discover and Set Studio Environment Variables",
11
+ namedArguments: { interactive: "interactive" },
11
12
  };
12
13
  export default async function (plop) {
13
14
  plop.setPrompt("directory", directoryPrompt);
@@ -0,0 +1,82 @@
1
+ // generators/kab/index.mjs
2
+ import { execSync } from "child_process";
3
+ import inquirer from "inquirer";
4
+ import { detectWorkspace } from "../../utils/nx-context.mjs";
5
+
6
+ export const metadata = {
7
+ key: "kab",
8
+ name: "Run Kab Target",
9
+ namedArguments: {
10
+ project: "project",
11
+ interactive: "interactive"
12
+ },
13
+ };
14
+
15
+ async function getProjectsWithTarget(target) {
16
+ try {
17
+ const output = execSync(`npx nx show projects --with-target ${target} --json`, {
18
+ encoding: "utf-8",
19
+ stdio: ["pipe", "pipe", "ignore"]
20
+ });
21
+ return JSON.parse(output);
22
+ } catch (error) {
23
+ return [];
24
+ }
25
+ }
26
+
27
+ export default async function (plop) {
28
+ const projects = await getProjectsWithTarget("kab");
29
+
30
+ if (projects.length === 0) {
31
+ console.warn("[kos-cli] No projects found with kab target");
32
+ // Still register the generator but it will fail gracefully
33
+ }
34
+
35
+ plop.setActionType("runKab", async function (answers) {
36
+ const isWorkspace = await detectWorkspace();
37
+
38
+ if (!isWorkspace) {
39
+ console.warn(
40
+ "[kos-cli] Not inside an Nx workspace. Cannot run kab target."
41
+ );
42
+ return "Skipped: Not a workspace";
43
+ }
44
+
45
+ const { project } = answers;
46
+
47
+ if (project === "all") {
48
+ console.log("[kos-cli] Running kab on all projects with kab target...");
49
+ try {
50
+ execSync("npx nx run-many --target=kab", {
51
+ stdio: "inherit",
52
+ });
53
+ return "Successfully ran kab on all projects";
54
+ } catch (error) {
55
+ throw new Error(`Failed to run kab on all projects: ${error.message}`);
56
+ }
57
+ } else {
58
+ console.log(`[kos-cli] Running kab on ${project}...`);
59
+ try {
60
+ execSync(`npx nx run ${project}:kab`, {
61
+ stdio: "inherit",
62
+ });
63
+ return `Successfully ran kab on ${project}`;
64
+ } catch (error) {
65
+ throw new Error(`Failed to run kab on ${project}: ${error.message}`);
66
+ }
67
+ }
68
+ });
69
+
70
+ plop.setGenerator("kab", {
71
+ description: "Run the kab target on a project",
72
+ prompts: [
73
+ {
74
+ type: "list",
75
+ name: "project",
76
+ message: "Select a project to run kab:",
77
+ choices: [...projects, new inquirer.Separator(), { name: "Run on all projects", value: "all" }],
78
+ },
79
+ ],
80
+ actions: () => [{ type: "runKab" }],
81
+ });
82
+ }
@@ -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
  },
@@ -20,13 +20,29 @@ export const metadata = {
20
20
  };
21
21
 
22
22
  export default async function (plop) {
23
- const allModels = await getAllModels();
24
- const modelChoices = allModels.map((m) => ({
25
- name: `${m.model} (${m.project})`,
26
- value: m.model,
27
- }));
23
+ // Check if we're in interactive mode by looking at process args
24
+ const isInteractive = process.argv.includes('-i') || process.argv.includes('--interactive');
25
+
26
+ // For interactive mode, use lazy loading. For non-interactive, load immediately.
27
+ let modelChoices;
28
+ if (isInteractive) {
29
+ modelChoices = async () => {
30
+ const allModels = await getAllModels();
31
+ return allModels.map((m) => ({
32
+ name: `${m.model} (${m.project})`,
33
+ value: m.model,
34
+ }));
35
+ };
36
+ } else {
37
+ const allModels = await getAllModels();
38
+ modelChoices = allModels.map((m) => ({
39
+ name: `${m.model} (${m.project})`,
40
+ value: m.model,
41
+ }));
42
+ }
28
43
 
29
44
  plop.setActionType("addFutureToModel", async function (answers) {
45
+ const allModels = await getAllModels();
30
46
  const modelProject = allModels.find(
31
47
  (m) => m.model === answers.modelName
32
48
  )?.project;