@holo-js/cli 0.2.6 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/bin/holo.mjs +417 -109
  2. package/dist/{broadcast-JBQWQZSO.mjs → broadcast-PJLFVZH4.mjs} +12 -12
  3. package/dist/cache-KR4ACOYD.mjs +137 -0
  4. package/dist/{cache-migrations-77TLXIVG.mjs → cache-migrations-J34RE4WH.mjs} +13 -13
  5. package/dist/{chunk-LXGQCG56.mjs → chunk-2XXJ76YC.mjs} +1 -1
  6. package/dist/chunk-3ICVWL2M.mjs +491 -0
  7. package/dist/{chunk-YEFJBN56.mjs → chunk-4VYR2ARA.mjs} +11 -8
  8. package/dist/{chunk-VP2E62DF.mjs → chunk-7KZVFDSI.mjs} +49 -349
  9. package/dist/chunk-AZ6NVJAP.mjs +360 -0
  10. package/dist/chunk-CT23GSEC.mjs +156 -0
  11. package/dist/{chunk-7B2RVYLL.mjs → chunk-FFTJKBQF.mjs} +293 -399
  12. package/dist/{chunk-KS5TWO75.mjs → chunk-I3RRWDLV.mjs} +7 -7
  13. package/dist/{chunk-J76GH2DR.mjs → chunk-L3YATEQY.mjs} +129 -86
  14. package/dist/{chunk-4K4CWMMP.mjs → chunk-L6FF22IV.mjs} +76 -61
  15. package/dist/{chunk-ILU426CF.mjs → chunk-PVVGQSUP.mjs} +482 -2
  16. package/dist/chunk-XBOVM6LO.mjs +41 -0
  17. package/dist/{chunk-I7QBCEV7.mjs → chunk-Y355VYRN.mjs} +5 -3
  18. package/dist/{chunk-VRGB6DIS.mjs → chunk-YJWHIQ45.mjs} +2 -0
  19. package/dist/{config-MD27U4FM.mjs → config-XVPV6DJW.mjs} +3 -3
  20. package/dist/{dev-L4Y2GU2E.mjs → dev-NTQTEY5B.mjs} +9 -8
  21. package/dist/{discovery-GWTBF5RZ.mjs → discovery-TMPUQQHI.mjs} +8 -6
  22. package/dist/{generators-VCYISHWO.mjs → generators-3FDCCJDC.mjs} +16 -15
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.mjs +419 -111
  25. package/dist/{media-migrations-BNVAPYEM.mjs → media-migrations-UJ6BMUSZ.mjs} +12 -12
  26. package/dist/plugins-USHY6SPF.mjs +24 -0
  27. package/dist/{queue-5BXSDFCO.mjs → queue-6U7JU4T6.mjs} +53 -17
  28. package/dist/{queue-D4LSWNS2.mjs → queue-VJEFD6SE.mjs} +55 -19
  29. package/dist/{queue-migrations-EF4AMMSY.mjs → queue-migrations-6YUUOKMH.mjs} +17 -14
  30. package/dist/{runtime-RPMZMTD4.mjs → runtime-FVRB4O2M.mjs} +8 -8
  31. package/dist/{runtime-GSXF4NB3.mjs → runtime-P5R7H3B4.mjs} +1 -1
  32. package/dist/runtime-worker.mjs +7 -1
  33. package/dist/{scaffold-NJ5VH73M.mjs → scaffold-F3AZDNPG.mjs} +9 -4
  34. package/dist/{security-K5PZS3E3.mjs → security-X4274RHX.mjs} +8 -7
  35. package/package.json +35 -8
  36. package/dist/broadcast-YGJFCEPP.mjs +0 -204
  37. package/dist/cache-HUGRWOHQ.mjs +0 -66
  38. package/dist/cache-OSJ4PD52.mjs +0 -66
  39. package/dist/cache-migrations-FKAHRP24.mjs +0 -173
  40. package/dist/chunk-AJLRAC5M.mjs +0 -497
  41. package/dist/chunk-C624G3R2.mjs +0 -3306
  42. package/dist/chunk-D7O4SU6N.mjs +0 -2
  43. package/dist/chunk-FGQ2I2YH.mjs +0 -22
  44. package/dist/chunk-LBJAJLKU.mjs +0 -25
  45. package/dist/dev-YPBQBEOE.mjs +0 -44
  46. package/dist/generators-H4NTV4DB.mjs +0 -520
  47. package/dist/media-migrations-NNB3DAQR.mjs +0 -106
  48. package/dist/queue-migrations-LXEWXJYT.mjs +0 -168
  49. package/dist/runtime-UKBJQFXM.mjs +0 -57
  50. package/dist/scaffold-VV3KTYGO.mjs +0 -139
  51. package/dist/security-JR4P7L2C.mjs +0 -71
package/dist/bin/holo.mjs CHANGED
@@ -16,28 +16,34 @@ import {
16
16
  resolveNewProjectInput,
17
17
  resolveStringFlag,
18
18
  splitCsv
19
- } from "../chunk-VRGB6DIS.mjs";
19
+ } from "../chunk-YJWHIQ45.mjs";
20
20
  import {
21
- hasProjectDependency
22
- } from "../chunk-FGQ2I2YH.mjs";
21
+ hasProjectDependency,
22
+ pinProjectDependencyVersions,
23
+ removeProjectDependency,
24
+ upsertProjectDependency
25
+ } from "../chunk-CT23GSEC.mjs";
23
26
  import {
24
27
  runWithSpinner,
25
- supportsSpinner,
26
28
  writeLine
27
- } from "../chunk-I7QBCEV7.mjs";
29
+ } from "../chunk-Y355VYRN.mjs";
28
30
  import {
31
+ ensureEmptyDirectory,
29
32
  fileExists
30
- } from "../chunk-LBJAJLKU.mjs";
31
- import "../chunk-D7O4SU6N.mjs";
32
- import "../chunk-VP2E62DF.mjs";
33
- import "../chunk-7B2RVYLL.mjs";
34
- import "../chunk-YEFJBN56.mjs";
35
- import "../chunk-J76GH2DR.mjs";
33
+ } from "../chunk-FFTJKBQF.mjs";
34
+ import "../chunk-4VYR2ARA.mjs";
35
+ import "../chunk-7KZVFDSI.mjs";
36
+ import "../chunk-L3YATEQY.mjs";
37
+ import "../chunk-3ICVWL2M.mjs";
38
+ import "../chunk-AZ6NVJAP.mjs";
36
39
  import {
40
+ APP_CONFIG_FILE_NAMES,
37
41
  SUPPORTED_AUTH_SOCIAL_PROVIDERS
38
- } from "../chunk-ILU426CF.mjs";
42
+ } from "../chunk-PVVGQSUP.mjs";
39
43
 
40
44
  // src/cli.ts
45
+ import { cp, mkdtemp, readFile as readFile2, rm, writeFile as writeFile2 } from "fs/promises";
46
+ import { tmpdir } from "os";
41
47
  import { resolve as resolve2 } from "path";
42
48
  import { clearConfigCache, resolveConfigCachePath } from "@holo-js/config";
43
49
 
@@ -107,12 +113,7 @@ async function generateProjectAppKey(projectRoot) {
107
113
  };
108
114
  }
109
115
 
110
- // src/cli.ts
111
- var AUTH_INSTALL_FEATURES = ["social", "workos", "clerk"];
112
- var AUTH_SOCIAL_PROVIDER_MODES = ["default", "specific"];
113
- var EVENTS_QUEUE_ACTIONS = ["skip", "enable"];
114
- var MODEL_GENERATOR_OPTIONS = ["migration", "observer", "seeder", "factory"];
115
- var COMMAND_LIST_DESCRIPTION_COLUMN = 32;
116
+ // src/command-executors.ts
116
117
  var runtimeModulePromise;
117
118
  var queueModulePromise;
118
119
  var cacheModulePromise;
@@ -125,63 +126,36 @@ var securityModulePromise;
125
126
  var devModulePromise;
126
127
  var projectConfigModulePromise;
127
128
  var projectDiscoveryModulePromise;
129
+ var projectPluginsModulePromise;
128
130
  var projectRuntimeModulePromise;
129
131
  var projectScaffoldModulePromise;
130
132
  var agentSkillsModulePromise;
131
133
  function loadRuntimeModule() {
132
- runtimeModulePromise ??= import("../runtime-RPMZMTD4.mjs");
134
+ runtimeModulePromise ??= import("../runtime-FVRB4O2M.mjs");
133
135
  return runtimeModulePromise;
134
136
  }
135
- function loadQueueModule() {
136
- queueModulePromise ??= import("../queue-D4LSWNS2.mjs");
137
- return queueModulePromise;
138
- }
139
- function loadCacheModule() {
140
- cacheModulePromise ??= import("../cache-OSJ4PD52.mjs");
141
- return cacheModulePromise;
142
- }
143
- function loadQueueMigrationsModule() {
144
- queueMigrationsModulePromise ??= import("../queue-migrations-LXEWXJYT.mjs");
145
- return queueMigrationsModulePromise;
146
- }
147
- function loadCacheMigrationsModule() {
148
- cacheMigrationsModulePromise ??= import("../cache-migrations-FKAHRP24.mjs");
149
- return cacheMigrationsModulePromise;
150
- }
151
- function loadMediaMigrationsModule() {
152
- mediaMigrationsModulePromise ??= import("../media-migrations-BNVAPYEM.mjs");
153
- return mediaMigrationsModulePromise;
154
- }
155
- function loadGeneratorsModule() {
156
- generatorsModulePromise ??= import("../generators-VCYISHWO.mjs");
157
- return generatorsModulePromise;
158
- }
159
- function loadBroadcastModule() {
160
- broadcastModulePromise ??= import("../broadcast-JBQWQZSO.mjs");
161
- return broadcastModulePromise;
162
- }
163
137
  function loadSecurityModule() {
164
- securityModulePromise ??= import("../security-K5PZS3E3.mjs");
138
+ securityModulePromise ??= import("../security-X4274RHX.mjs");
165
139
  return securityModulePromise;
166
140
  }
167
- function loadDevModule() {
168
- devModulePromise ??= import("../dev-YPBQBEOE.mjs");
169
- return devModulePromise;
170
- }
171
141
  function loadProjectConfigModule() {
172
- projectConfigModulePromise ??= import("../config-MD27U4FM.mjs");
142
+ projectConfigModulePromise ??= import("../config-XVPV6DJW.mjs");
173
143
  return projectConfigModulePromise;
174
144
  }
175
145
  function loadProjectDiscoveryModule() {
176
- projectDiscoveryModulePromise ??= import("../discovery-GWTBF5RZ.mjs");
146
+ projectDiscoveryModulePromise ??= import("../discovery-TMPUQQHI.mjs");
177
147
  return projectDiscoveryModulePromise;
178
148
  }
149
+ function loadProjectPluginsModule() {
150
+ projectPluginsModulePromise ??= import("../plugins-USHY6SPF.mjs");
151
+ return projectPluginsModulePromise;
152
+ }
179
153
  function loadProjectRuntimeModule() {
180
- projectRuntimeModulePromise ??= import("../runtime-GSXF4NB3.mjs");
154
+ projectRuntimeModulePromise ??= import("../runtime-P5R7H3B4.mjs");
181
155
  return projectRuntimeModulePromise;
182
156
  }
183
157
  function loadProjectScaffoldModule() {
184
- projectScaffoldModulePromise ??= import("../scaffold-NJ5VH73M.mjs");
158
+ projectScaffoldModulePromise ??= import("../scaffold-F3AZDNPG.mjs");
185
159
  return projectScaffoldModulePromise;
186
160
  }
187
161
  function loadAgentSkillsModule() {
@@ -189,63 +163,73 @@ function loadAgentSkillsModule() {
189
163
  return agentSkillsModulePromise;
190
164
  }
191
165
  async function resolveRuntimeExecutor(runtimeExecutor) {
192
- return runtimeExecutor ?? (await loadRuntimeModule()).withRuntimeEnvironment;
166
+ runtimeModulePromise ??= import("../runtime-FVRB4O2M.mjs");
167
+ return runtimeExecutor ?? (await runtimeModulePromise).withRuntimeEnvironment;
193
168
  }
194
- var projectExecutorLoaders = {
195
- runProjectPrepare: async () => (await loadDevModule()).runProjectPrepare,
196
- runProjectDevServer: async () => (await loadDevModule()).runProjectDevServer,
197
- runProjectBuild: async () => (await loadDevModule()).runProjectBuild,
198
- runProjectStartServer: async () => (await loadDevModule()).runProjectStartServer,
199
- runProjectDependencyInstall: async () => (await loadDevModule()).runProjectDependencyInstall
200
- };
201
- async function resolveExecutor(executors, loaders, key) {
169
+ async function resolveExecutor(executors, loader, key) {
202
170
  const existing = executors[key];
203
- if (existing) {
204
- return existing;
205
- }
206
- return await loaders[key]();
171
+ return existing ? existing : await loader();
207
172
  }
208
- async function resolveProjectExecutor(projectExecutors, key) {
209
- return await resolveExecutor(projectExecutors, projectExecutorLoaders, key);
173
+ async function resolveProjectExecutor(executors, key) {
174
+ devModulePromise ??= import("../dev-NTQTEY5B.mjs");
175
+ return resolveExecutor(executors, async () => (await devModulePromise)[key], key);
210
176
  }
211
- var queueExecutorLoaders = {
212
- runQueueFailedTableCommand: async () => (await loadQueueMigrationsModule()).runQueueFailedTableCommand,
213
- runQueueTableCommand: async () => (await loadQueueMigrationsModule()).runQueueTableCommand,
214
- runQueueFailedCommand: async () => (await loadQueueModule()).runQueueFailedCommand,
215
- runQueueFlushCommand: async () => (await loadQueueModule()).runQueueFlushCommand,
216
- runQueueWorkCommand: async () => (await loadQueueModule()).runQueueWorkCommand,
217
- runQueueForgetCommand: async () => (await loadQueueModule()).runQueueForgetCommand,
218
- runQueueListen: async () => (await loadQueueModule()).runQueueListen,
219
- runQueueRestartCommand: async () => (await loadQueueModule()).runQueueRestartCommand,
220
- runQueueRetryCommand: async () => (await loadQueueModule()).runQueueRetryCommand,
221
- runQueueClearCommand: async () => (await loadQueueModule()).runQueueClearCommand
222
- };
223
- var cacheExecutorLoaders = {
224
- runCacheTableCommand: async () => (await loadCacheMigrationsModule()).runCacheTableCommand,
225
- runCacheClearCommand: async () => (await loadCacheModule()).runCacheClearCommand,
226
- runCacheForgetCommand: async () => (await loadCacheModule()).runCacheForgetCommand
227
- };
228
- var mediaExecutorLoaders = {
229
- runMediaTableCommand: async () => (await loadMediaMigrationsModule()).runMediaTableCommand
230
- };
231
- var broadcastExecutorLoaders = {
232
- runBroadcastWorkCommand: async () => (await loadBroadcastModule()).runBroadcastWorkCommand
233
- };
234
- async function resolveQueueExecutor(queueExecutors, key) {
235
- return await resolveExecutor(queueExecutors, queueExecutorLoaders, key);
177
+ async function resolveQueueExecutor(executors, key) {
178
+ return resolveExecutor(executors, async () => {
179
+ if (key === "runQueueFailedTableCommand" || key === "runQueueTableCommand") {
180
+ queueMigrationsModulePromise ??= import("../queue-migrations-6YUUOKMH.mjs");
181
+ const migrations = await queueMigrationsModulePromise;
182
+ return key === "runQueueFailedTableCommand" ? migrations.runQueueFailedTableCommand : migrations.runQueueTableCommand;
183
+ }
184
+ queueModulePromise ??= import("../queue-VJEFD6SE.mjs");
185
+ const queue = await queueModulePromise;
186
+ const resolved = {
187
+ runQueueFailedCommand: queue.runQueueFailedCommand,
188
+ runQueueFlushCommand: queue.runQueueFlushCommand,
189
+ runQueueWorkCommand: queue.runQueueWorkCommand,
190
+ runQueueForgetCommand: queue.runQueueForgetCommand,
191
+ runQueueListen: queue.runQueueListen,
192
+ runQueueRestartCommand: queue.runQueueRestartCommand,
193
+ runQueueRetryCommand: queue.runQueueRetryCommand,
194
+ runQueueClearCommand: queue.runQueueClearCommand
195
+ };
196
+ return resolved[key];
197
+ }, key);
236
198
  }
237
- async function resolveCacheExecutor(cacheExecutors, key) {
238
- return await resolveExecutor(cacheExecutors, cacheExecutorLoaders, key);
199
+ async function resolveCacheExecutor(executors, key) {
200
+ return resolveExecutor(executors, async () => {
201
+ if (key === "runCacheTableCommand") {
202
+ cacheMigrationsModulePromise ??= import("../cache-migrations-J34RE4WH.mjs");
203
+ return (await cacheMigrationsModulePromise).runCacheTableCommand;
204
+ }
205
+ cacheModulePromise ??= import("../cache-KR4ACOYD.mjs");
206
+ const cache = await cacheModulePromise;
207
+ const resolved = {
208
+ runCacheClearCommand: cache.runCacheClearCommand,
209
+ runCacheForgetCommand: cache.runCacheForgetCommand
210
+ };
211
+ return resolved[key];
212
+ }, key);
239
213
  }
240
- async function resolveMediaExecutor(mediaExecutors, key) {
241
- return await resolveExecutor(mediaExecutors, mediaExecutorLoaders, key);
214
+ async function resolveMediaExecutor(executors, key) {
215
+ mediaMigrationsModulePromise ??= import("../media-migrations-UJ6BMUSZ.mjs");
216
+ return resolveExecutor(executors, async () => (await mediaMigrationsModulePromise)[key], key);
242
217
  }
243
- async function resolveBroadcastExecutor(broadcastExecutors, key) {
244
- return await resolveExecutor(broadcastExecutors, broadcastExecutorLoaders, key);
218
+ async function resolveBroadcastExecutor(executors, key) {
219
+ broadcastModulePromise ??= import("../broadcast-PJLFVZH4.mjs");
220
+ return resolveExecutor(executors, async () => (await broadcastModulePromise)[key], key);
245
221
  }
246
222
  async function resolveGeneratorCommand(key) {
247
- return (await loadGeneratorsModule())[key];
223
+ generatorsModulePromise ??= import("../generators-3FDCCJDC.mjs");
224
+ return (await generatorsModulePromise)[key];
248
225
  }
226
+
227
+ // src/cli.ts
228
+ var AUTH_INSTALL_FEATURES = ["social", "workos", "clerk"];
229
+ var AUTH_SOCIAL_PROVIDER_MODES = ["default", "specific"];
230
+ var EVENTS_QUEUE_ACTIONS = ["skip", "enable"];
231
+ var MODEL_GENERATOR_OPTIONS = ["migration", "observer", "seeder", "factory"];
232
+ var COMMAND_LIST_DESCRIPTION_COLUMN = 32;
249
233
  function createCommandContext(io, projectRoot, loadProject, input) {
250
234
  return {
251
235
  cwd: io.cwd,
@@ -327,6 +311,130 @@ async function runProjectDependencyInstallForProject(context, projectExecutors,
327
311
  writeLine(context.stdout, " - installed dependencies");
328
312
  }
329
313
  }
314
+ function formatPluginLabel(plugin) {
315
+ return plugin.name ? `${plugin.name} (${plugin.id})` : plugin.id;
316
+ }
317
+ function formatPluginContributionLines(plugin) {
318
+ const contributes = plugin.contributes;
319
+ if (!contributes) {
320
+ return [];
321
+ }
322
+ const lines = [];
323
+ if (contributes.framework) {
324
+ lines.push(`framework: ${contributes.framework.displayName}`);
325
+ }
326
+ if (contributes.dependencies?.holo?.length) {
327
+ lines.push(`holo packages: ${contributes.dependencies.holo.join(", ")}`);
328
+ }
329
+ if (contributes.dependencies?.runtime?.length) {
330
+ lines.push(`runtime packages: ${contributes.dependencies.runtime.join(", ")}`);
331
+ }
332
+ if (contributes.config?.files?.length) {
333
+ lines.push(`config files: ${contributes.config.files.join(", ")}`);
334
+ }
335
+ if (contributes.config?.env?.length) {
336
+ lines.push(`env keys: ${contributes.config.env.join(", ")}`);
337
+ }
338
+ if (contributes.broadcast?.drivers) {
339
+ const driverNames = Object.keys(contributes.broadcast.drivers);
340
+ if (driverNames.length > 0) {
341
+ lines.push(`broadcast drivers: ${driverNames.join(", ")}`);
342
+ }
343
+ }
344
+ if (contributes.cache?.drivers) {
345
+ const driverNames = Object.keys(contributes.cache.drivers);
346
+ if (driverNames.length > 0) {
347
+ lines.push(`cache drivers: ${driverNames.join(", ")}`);
348
+ }
349
+ }
350
+ if (contributes.queue?.drivers) {
351
+ const driverNames = Object.keys(contributes.queue.drivers);
352
+ if (driverNames.length > 0) {
353
+ lines.push(`queue drivers: ${driverNames.join(", ")}`);
354
+ }
355
+ }
356
+ if (contributes.mail?.drivers) {
357
+ const driverNames = Object.keys(contributes.mail.drivers);
358
+ if (driverNames.length > 0) {
359
+ lines.push(`mail drivers: ${driverNames.join(", ")}`);
360
+ }
361
+ }
362
+ if (contributes.notifications?.channels) {
363
+ const channelNames = Object.keys(contributes.notifications.channels);
364
+ if (channelNames.length > 0) {
365
+ lines.push(`notification channels: ${channelNames.join(", ")}`);
366
+ }
367
+ }
368
+ if (contributes.runtime?.boot) {
369
+ lines.push(`runtime boot: ${contributes.runtime.boot}`);
370
+ }
371
+ if (contributes.cli?.commands) {
372
+ lines.push(`cli commands: ${contributes.cli.commands}`);
373
+ }
374
+ if (contributes.migrations?.publish) {
375
+ lines.push(`migration publisher: ${contributes.migrations.publish}`);
376
+ }
377
+ return lines;
378
+ }
379
+ function writePluginDetails(context, loadedPlugin) {
380
+ writeLine(context.stdout, `Plugin: ${formatPluginLabel(loadedPlugin.definition)}`);
381
+ writeLine(context.stdout, ` - package: ${loadedPlugin.packageName}`);
382
+ if (loadedPlugin.definition.description) {
383
+ writeLine(context.stdout, ` - description: ${loadedPlugin.definition.description}`);
384
+ }
385
+ const contributionLines = formatPluginContributionLines(loadedPlugin.definition);
386
+ if (contributionLines.length === 0) {
387
+ writeLine(context.stdout, " - contributions: none");
388
+ return;
389
+ }
390
+ for (const line of contributionLines) {
391
+ writeLine(context.stdout, ` - ${line}`);
392
+ }
393
+ }
394
+ async function readPackageJsonSnapshot(projectRoot) {
395
+ return await readFile2(resolve2(projectRoot, "package.json"), "utf8");
396
+ }
397
+ async function restorePackageJsonSnapshot(projectRoot, snapshot) {
398
+ await writeFile2(resolve2(projectRoot, "package.json"), snapshot);
399
+ }
400
+ async function readAppConfigSnapshot(projectRoot) {
401
+ for (const fileName of APP_CONFIG_FILE_NAMES) {
402
+ const path = resolve2(projectRoot, fileName);
403
+ if (await fileExists(path)) {
404
+ return {
405
+ path,
406
+ contents: await readFile2(path, "utf8")
407
+ };
408
+ }
409
+ }
410
+ return void 0;
411
+ }
412
+ async function restoreAppConfigSnapshot(snapshot) {
413
+ if (!snapshot) {
414
+ return;
415
+ }
416
+ await writeFile2(snapshot.path, snapshot.contents);
417
+ }
418
+ async function readDirectorySnapshot(projectRoot, relativePath) {
419
+ const path = resolve2(projectRoot, relativePath);
420
+ if (!await fileExists(path)) {
421
+ return { path };
422
+ }
423
+ const snapshotPath = await mkdtemp(resolve2(tmpdir(), "holo-cli-plugin-add-"));
424
+ await cp(path, snapshotPath, { recursive: true, force: true });
425
+ return { path, snapshotPath };
426
+ }
427
+ async function restoreDirectorySnapshot(snapshot) {
428
+ await rm(snapshot.path, { recursive: true, force: true });
429
+ if (snapshot.snapshotPath) {
430
+ await cp(snapshot.snapshotPath, snapshot.path, { recursive: true, force: true });
431
+ }
432
+ }
433
+ async function cleanupDirectorySnapshot(snapshot) {
434
+ if (snapshot.snapshotPath) {
435
+ await rm(snapshot.snapshotPath, { recursive: true, force: true });
436
+ }
437
+ }
330
438
  function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, projectExecutors = {}, broadcastExecutors = {}, securityExecutors = {}, cacheExecutors = {}, mediaExecutors = {}) {
331
439
  return [
332
440
  {
@@ -347,7 +455,12 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
347
455
  usage: "holo new <name> [--framework <nuxt|next|sveltekit>] [--database <sqlite|mysql|postgres>] [--package-manager <bun|npm|pnpm|yarn>] [--package <storage|events|queue|validation|forms|auth|authorization|notifications|mail|broadcast|realtime|security|cache>] [--storage-default-disk <local|public>]",
348
456
  source: "internal",
349
457
  async prepare(input) {
350
- const resolved = await resolveNewProjectInput(context, input);
458
+ const resolved = await resolveNewProjectInput(
459
+ context,
460
+ input,
461
+ void 0,
462
+ (projectName) => ensureEmptyDirectory(resolve2(context.cwd, projectName), projectName)
463
+ );
351
464
  return {
352
465
  args: [resolved.projectName],
353
466
  flags: {
@@ -386,11 +499,11 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
386
499
  writeLine(context.stdout, `Created Holo project: ${targetDir}`);
387
500
  await runWithSpinner(
388
501
  context,
389
- "Installing dependencies...",
502
+ `Installing dependencies with ${packageManager}...`,
390
503
  () => runProjectDependencyInstallForProject(context, projectExecutors, targetDir, {
391
- writeStatus: !supportsSpinner(context)
504
+ writeStatus: false
392
505
  }),
393
- "Dependencies installed."
506
+ `Dependencies installed with ${packageManager}.`
394
507
  );
395
508
  writeLine(context.stdout);
396
509
  writeLine(context.stdout, "Next steps");
@@ -751,6 +864,196 @@ function createInternalCommands(context, runtimeExecutor, queueExecutors = {}, p
751
864
  await runProjectDependencyInstallAfterPackageJsonUpdate(context, projectExecutors, result.updatedPackageJson);
752
865
  }
753
866
  },
867
+ {
868
+ name: "plugin:add",
869
+ aliases: ["plugins:add"],
870
+ description: "Install and activate a Holo plugin package.",
871
+ usage: "holo plugin:add <package>",
872
+ source: "internal",
873
+ async prepare(input) {
874
+ const packageName = await ensureRequiredArg(context, input, 0, "Plugin package");
875
+ return { args: [packageName], flags: {} };
876
+ },
877
+ async run(commandContext) {
878
+ const packageName = String(commandContext.args[0] ?? "");
879
+ const plugins = await loadProjectPluginsModule();
880
+ const packageJsonSnapshot = await readPackageJsonSnapshot(context.projectRoot);
881
+ const appConfigSnapshot = await readAppConfigSnapshot(context.projectRoot);
882
+ const holoDirectorySnapshot = await readDirectorySnapshot(context.projectRoot, ".holo-js");
883
+ let dependencyInstallSucceeded = false;
884
+ let updatedDependencies = false;
885
+ let updatedPackageJson = false;
886
+ let loadedPlugin;
887
+ let contributedDependencies = [];
888
+ let updatedContributedDependencies = false;
889
+ let activated = false;
890
+ try {
891
+ updatedPackageJson = await upsertProjectDependency(context.projectRoot, packageName);
892
+ updatedDependencies = updatedPackageJson || updatedDependencies;
893
+ if (updatedPackageJson) {
894
+ await runProjectDependencyInstallForProject(context, projectExecutors, context.projectRoot);
895
+ dependencyInstallSucceeded = true;
896
+ await pinProjectDependencyVersions(context.projectRoot, [packageName]);
897
+ }
898
+ loadedPlugin = await plugins.loadHoloPluginFromPackage(context.projectRoot, packageName);
899
+ contributedDependencies = [
900
+ ...loadedPlugin.definition.contributes?.dependencies?.holo ?? [],
901
+ ...loadedPlugin.definition.contributes?.dependencies?.runtime ?? []
902
+ ];
903
+ for (const dependencyName of contributedDependencies) {
904
+ const updatedContributedDependency = await upsertProjectDependency(context.projectRoot, dependencyName);
905
+ updatedContributedDependencies = updatedContributedDependency || updatedContributedDependencies;
906
+ }
907
+ updatedDependencies = updatedContributedDependencies || updatedDependencies;
908
+ if (updatedContributedDependencies) {
909
+ await runProjectDependencyInstallForProject(context, projectExecutors, context.projectRoot);
910
+ dependencyInstallSucceeded = true;
911
+ await pinProjectDependencyVersions(context.projectRoot, contributedDependencies);
912
+ }
913
+ activated = await plugins.activateProjectPlugin(context.projectRoot, packageName);
914
+ if (activated) {
915
+ const runProjectPrepare = await resolveProjectExecutor(projectExecutors, "runProjectPrepare");
916
+ await runProjectPrepare(context.projectRoot, context);
917
+ }
918
+ } catch (error) {
919
+ await restoreAppConfigSnapshot(appConfigSnapshot);
920
+ await restorePackageJsonSnapshot(context.projectRoot, packageJsonSnapshot);
921
+ await restoreDirectorySnapshot(holoDirectorySnapshot);
922
+ if (updatedDependencies && dependencyInstallSucceeded) {
923
+ await runProjectDependencyInstallForProject(context, projectExecutors, context.projectRoot).catch(() => void 0);
924
+ }
925
+ await cleanupDirectorySnapshot(holoDirectorySnapshot);
926
+ throw error;
927
+ }
928
+ writeLine(context.stdout, `Installed Holo plugin: ${formatPluginLabel(loadedPlugin.definition)}`);
929
+ writeLine(context.stdout, ` - package: ${updatedPackageJson ? "added" : "already present"} ${packageName}`);
930
+ if (contributedDependencies.length > 0) {
931
+ writeLine(
932
+ context.stdout,
933
+ ` - dependencies: ${updatedContributedDependencies ? "updated" : "already present"} ${contributedDependencies.join(", ")}`
934
+ );
935
+ }
936
+ writeLine(context.stdout, ` - activation: ${activated ? "updated config/app.ts" : "already active"}`);
937
+ if (activated) {
938
+ writeLine(context.stdout, " - refreshed generated artifacts");
939
+ }
940
+ for (const line of formatPluginContributionLines(loadedPlugin.definition)) {
941
+ writeLine(context.stdout, ` - ${line}`);
942
+ }
943
+ await cleanupDirectorySnapshot(holoDirectorySnapshot);
944
+ }
945
+ },
946
+ {
947
+ name: "plugin:list",
948
+ aliases: ["plugins:list"],
949
+ description: "List active Holo plugins.",
950
+ usage: "holo plugin:list",
951
+ source: "internal",
952
+ async prepare() {
953
+ return { args: [], flags: {} };
954
+ },
955
+ async run() {
956
+ const plugins = await loadProjectPluginsModule();
957
+ const resolvedPlugins = await plugins.resolveProjectPlugins(context.projectRoot);
958
+ writeLine(context.stdout, "Active Holo plugins:");
959
+ if (resolvedPlugins.length === 0) {
960
+ writeLine(context.stdout, " (none)");
961
+ return;
962
+ }
963
+ for (const resolvedPlugin of resolvedPlugins) {
964
+ if (resolvedPlugin.loaded) {
965
+ writeLine(context.stdout, ` - ${resolvedPlugin.packageName}: ${formatPluginLabel(resolvedPlugin.loaded.definition)}`);
966
+ continue;
967
+ }
968
+ writeLine(context.stdout, ` - ${resolvedPlugin.packageName}: failed`);
969
+ if (resolvedPlugin.error) {
970
+ writeLine(context.stdout, ` ${resolvedPlugin.error}`);
971
+ }
972
+ }
973
+ }
974
+ },
975
+ {
976
+ name: "plugin:remove",
977
+ aliases: ["plugins:remove"],
978
+ description: "Deactivate a Holo plugin package.",
979
+ usage: "holo plugin:remove <package> [--uninstall]",
980
+ source: "internal",
981
+ async prepare(input) {
982
+ const packageName = await ensureRequiredArg(context, input, 0, "Plugin package");
983
+ return {
984
+ args: [packageName],
985
+ flags: {
986
+ ...resolveBooleanFlag(input.flags, "uninstall") === true ? { uninstall: true } : {}
987
+ }
988
+ };
989
+ },
990
+ async run(commandContext) {
991
+ const packageName = String(commandContext.args[0] ?? "");
992
+ const plugins = await loadProjectPluginsModule();
993
+ const deactivated = await plugins.deactivateProjectPlugin(context.projectRoot, packageName);
994
+ const uninstalled = commandContext.flags.uninstall === true ? await removeProjectDependency(context.projectRoot, packageName) : false;
995
+ if (uninstalled) {
996
+ await runProjectDependencyInstallForProject(context, projectExecutors, context.projectRoot);
997
+ }
998
+ if (deactivated || uninstalled) {
999
+ const runProjectPrepare = await resolveProjectExecutor(projectExecutors, "runProjectPrepare");
1000
+ await runProjectPrepare(context.projectRoot, context);
1001
+ }
1002
+ writeLine(context.stdout, deactivated ? "Removed Holo plugin activation." : "Holo plugin was not active.");
1003
+ writeLine(context.stdout, ` - package: ${packageName}`);
1004
+ if (commandContext.flags.uninstall === true) {
1005
+ writeLine(context.stdout, ` - dependency: ${uninstalled ? "removed from package.json" : "not present in package.json"}`);
1006
+ } else {
1007
+ writeLine(context.stdout, " - dependency: left installed");
1008
+ }
1009
+ }
1010
+ },
1011
+ {
1012
+ name: "plugin:info",
1013
+ aliases: ["plugins:info"],
1014
+ description: "Show metadata for a Holo plugin package.",
1015
+ usage: "holo plugin:info <package>",
1016
+ source: "internal",
1017
+ async prepare(input) {
1018
+ const packageName = await ensureRequiredArg(context, input, 0, "Plugin package");
1019
+ return { args: [packageName], flags: {} };
1020
+ },
1021
+ async run(commandContext) {
1022
+ const packageName = String(commandContext.args[0] ?? "");
1023
+ const plugins = await loadProjectPluginsModule();
1024
+ const loadedPlugin = await plugins.loadHoloPluginFromPackage(context.projectRoot, packageName);
1025
+ writePluginDetails(context, loadedPlugin);
1026
+ }
1027
+ },
1028
+ {
1029
+ name: "plugin:doctor",
1030
+ aliases: ["plugins:doctor"],
1031
+ description: "Validate active Holo plugin packages.",
1032
+ usage: "holo plugin:doctor",
1033
+ source: "internal",
1034
+ async prepare() {
1035
+ return { args: [], flags: {} };
1036
+ },
1037
+ async run() {
1038
+ const plugins = await loadProjectPluginsModule();
1039
+ const resolvedPlugins = await plugins.resolveProjectPlugins(context.projectRoot);
1040
+ const failedPlugins = resolvedPlugins.filter((resolvedPlugin) => !resolvedPlugin.loaded);
1041
+ if (resolvedPlugins.length === 0) {
1042
+ writeLine(context.stdout, "No active Holo plugins.");
1043
+ return;
1044
+ }
1045
+ for (const resolvedPlugin of resolvedPlugins) {
1046
+ if (resolvedPlugin.loaded) {
1047
+ writeLine(context.stdout, `Loaded ${resolvedPlugin.packageName}: ${formatPluginLabel(resolvedPlugin.loaded.definition)}`);
1048
+ continue;
1049
+ }
1050
+ writeLine(context.stdout, `Failed ${resolvedPlugin.packageName}: ${resolvedPlugin.error ?? "Unknown plugin loading error."}`);
1051
+ }
1052
+ if (failedPlugins.length > 0) {
1053
+ throw new Error(`${failedPlugins.length} Holo ${failedPlugins.length === 1 ? "plugin" : "plugins"} failed validation.`);
1054
+ }
1055
+ }
1056
+ },
754
1057
  {
755
1058
  name: "auth:notifications:publish",
756
1059
  description: "Publish editable auth notification definitions into the application.",
@@ -1672,10 +1975,15 @@ async function runCli(argv, io) {
1672
1975
  };
1673
1976
  const internalCommands = createInternalCommands(internalContext);
1674
1977
  const registry = [...internalCommands];
1675
- const canSkipAppDiscovery = requestedCommandName === "config:cache" || requestedCommandName === "config:clear" || requestedCommandName === "key:generate" || requestedCommandName === "new" || requestedCommandName === "install" || requestedCommandName === "agents:install" || requestedCommandName === "agent:install" || requestedCommandName === "ai:install" || requestedCommandName === "auth:notifications:publish" || requestedCommandName === "prepare" || requestedCommandName === "dev" || requestedCommandName === "build" || requestedCommandName === "cache:table" || requestedCommandName === "cache:clear" || requestedCommandName === "cache:forget" || requestedCommandName === "media:table" || requestedCommandName === "broadcast:work" || requestedCommandName === "queue:table" || requestedCommandName === "queue:failed-table" || requestedCommandName === "queue:work" || requestedCommandName === "queue:listen" || requestedCommandName === "queue:failed" || requestedCommandName === "queue:retry" || requestedCommandName === "queue:forget" || requestedCommandName === "queue:flush" || requestedCommandName === "queue:restart" || requestedCommandName === "queue:clear" || requestedCommandName === "rate-limit:clear";
1978
+ const requestedInternalCommand = requestedCommandName ? findCommand(registry, requestedCommandName) : void 0;
1979
+ const canSkipAppDiscovery = requestedCommandName === "config:cache" || requestedCommandName === "config:clear" || requestedCommandName === "key:generate" || requestedCommandName === "new" || requestedCommandName === "install" || requestedCommandName === "agents:install" || requestedCommandName === "agent:install" || requestedCommandName === "ai:install" || requestedCommandName === "auth:notifications:publish" || requestedCommandName === "prepare" || requestedCommandName === "dev" || requestedCommandName === "build" || requestedCommandName === "cache:table" || requestedCommandName === "cache:clear" || requestedCommandName === "cache:forget" || requestedCommandName === "media:table" || requestedCommandName === "broadcast:work" || requestedCommandName === "queue:table" || requestedCommandName === "queue:failed-table" || requestedCommandName === "queue:work" || requestedCommandName === "queue:listen" || requestedCommandName === "queue:failed" || requestedCommandName === "queue:retry" || requestedCommandName === "queue:forget" || requestedCommandName === "queue:flush" || requestedCommandName === "queue:restart" || requestedCommandName === "queue:clear" || requestedCommandName === "rate-limit:clear" || requestedCommandName === "plugin:add" || requestedCommandName === "plugins:add" || requestedCommandName === "plugin:list" || requestedCommandName === "plugins:list" || requestedCommandName === "plugin:remove" || requestedCommandName === "plugins:remove" || requestedCommandName === "plugin:info" || requestedCommandName === "plugins:info" || requestedCommandName === "plugin:doctor" || requestedCommandName === "plugins:doctor" || typeof requestedInternalCommand !== "undefined" && requestedInternalCommand.name !== "list";
1676
1980
  if (!canSkipAppDiscovery) {
1677
1981
  const initialProject = await loadProject();
1678
- const appCommands = (await (await loadProjectDiscoveryModule()).discoverAppCommands(projectRoot, initialProject.config)).map((entry) => createAppCommandDefinition(entry));
1982
+ const pluginCommands = await (await loadProjectPluginsModule()).loadProjectPluginCommands(projectRoot);
1983
+ const appCommands = [
1984
+ ...pluginCommands,
1985
+ ...await (await loadProjectDiscoveryModule()).discoverAppCommands(projectRoot, initialProject.config)
1986
+ ].map((entry) => createAppCommandDefinition(entry));
1679
1987
  for (const appCommand of appCommands) {
1680
1988
  const duplicate = findCommandConflict(registry, appCommand);
1681
1989
  if (duplicate) {
@@ -1,25 +1,25 @@
1
- import {
2
- writeLine
3
- } from "./chunk-I7QBCEV7.mjs";
4
1
  import {
5
2
  initializeProjectRuntime
6
- } from "./chunk-KS5TWO75.mjs";
7
- import "./chunk-LBJAJLKU.mjs";
8
- import "./chunk-D7O4SU6N.mjs";
3
+ } from "./chunk-I3RRWDLV.mjs";
9
4
  import {
10
- prepareProjectDiscovery
11
- } from "./chunk-VP2E62DF.mjs";
12
- import "./chunk-7B2RVYLL.mjs";
5
+ writeLine
6
+ } from "./chunk-Y355VYRN.mjs";
7
+ import "./chunk-FFTJKBQF.mjs";
13
8
  import {
14
9
  loadProjectConfig
15
- } from "./chunk-YEFJBN56.mjs";
10
+ } from "./chunk-4VYR2ARA.mjs";
11
+ import {
12
+ prepareProjectDiscovery
13
+ } from "./chunk-7KZVFDSI.mjs";
16
14
  import {
17
15
  loadGeneratedProjectRegistry
18
- } from "./chunk-J76GH2DR.mjs";
16
+ } from "./chunk-L3YATEQY.mjs";
17
+ import "./chunk-3ICVWL2M.mjs";
18
+ import "./chunk-AZ6NVJAP.mjs";
19
19
  import {
20
20
  importProjectModule,
21
21
  resolveProjectPackageImportSpecifier
22
- } from "./chunk-ILU426CF.mjs";
22
+ } from "./chunk-PVVGQSUP.mjs";
23
23
 
24
24
  // src/broadcast.ts
25
25
  import { basename, extname, resolve } from "path";