@beignet/cli 0.0.37 → 0.0.39

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 (113) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +138 -101
  3. package/dist/choices.d.ts +17 -21
  4. package/dist/choices.d.ts.map +1 -1
  5. package/dist/choices.js +21 -67
  6. package/dist/choices.js.map +1 -1
  7. package/dist/config.d.ts +1 -1
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +1 -1
  10. package/dist/config.js.map +1 -1
  11. package/dist/create-prompts.d.ts +5 -6
  12. package/dist/create-prompts.d.ts.map +1 -1
  13. package/dist/create-prompts.js +15 -15
  14. package/dist/create-prompts.js.map +1 -1
  15. package/dist/create.d.ts +11 -2
  16. package/dist/create.d.ts.map +1 -1
  17. package/dist/create.js +38 -28
  18. package/dist/create.js.map +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +149 -47
  21. package/dist/index.js.map +1 -1
  22. package/dist/inspect.js +69 -16
  23. package/dist/inspect.js.map +1 -1
  24. package/dist/lib.d.ts +1 -1
  25. package/dist/lib.d.ts.map +1 -1
  26. package/dist/lint.d.ts.map +1 -1
  27. package/dist/lint.js +27 -6
  28. package/dist/lint.js.map +1 -1
  29. package/dist/make/inbox.js +10 -10
  30. package/dist/make/inbox.js.map +1 -1
  31. package/dist/make/payments.d.ts +2 -1
  32. package/dist/make/payments.d.ts.map +1 -1
  33. package/dist/make/payments.js +18 -14
  34. package/dist/make/payments.js.map +1 -1
  35. package/dist/make/shared.d.ts +11 -4
  36. package/dist/make/shared.d.ts.map +1 -1
  37. package/dist/make/shared.js +56 -45
  38. package/dist/make/shared.js.map +1 -1
  39. package/dist/make/tenancy.js +8 -8
  40. package/dist/make/tenancy.js.map +1 -1
  41. package/dist/make.d.ts +3 -2
  42. package/dist/make.d.ts.map +1 -1
  43. package/dist/make.js +481 -200
  44. package/dist/make.js.map +1 -1
  45. package/dist/mcp.d.ts.map +1 -1
  46. package/dist/mcp.js +15 -11
  47. package/dist/mcp.js.map +1 -1
  48. package/dist/operational-error-reporting.d.ts +15 -0
  49. package/dist/operational-error-reporting.d.ts.map +1 -0
  50. package/dist/operational-error-reporting.js +42 -0
  51. package/dist/operational-error-reporting.js.map +1 -0
  52. package/dist/outbox.d.ts.map +1 -1
  53. package/dist/outbox.js +73 -0
  54. package/dist/outbox.js.map +1 -1
  55. package/dist/provider-add.d.ts +21 -3
  56. package/dist/provider-add.d.ts.map +1 -1
  57. package/dist/provider-add.js +117 -81
  58. package/dist/provider-add.js.map +1 -1
  59. package/dist/provider-audit.js +3 -3
  60. package/dist/provider-audit.js.map +1 -1
  61. package/dist/schedule.d.ts.map +1 -1
  62. package/dist/schedule.js +28 -1
  63. package/dist/schedule.js.map +1 -1
  64. package/dist/task.d.ts.map +1 -1
  65. package/dist/task.js +38 -5
  66. package/dist/task.js.map +1 -1
  67. package/dist/templates/base.d.ts +1 -1
  68. package/dist/templates/base.d.ts.map +1 -1
  69. package/dist/templates/base.js +15 -15
  70. package/dist/templates/base.js.map +1 -1
  71. package/dist/templates/index.d.ts +2 -2
  72. package/dist/templates/index.d.ts.map +1 -1
  73. package/dist/templates/index.js +7 -7
  74. package/dist/templates/index.js.map +1 -1
  75. package/dist/templates/server.d.ts +1 -1
  76. package/dist/templates/server.d.ts.map +1 -1
  77. package/dist/templates/server.js +22 -18
  78. package/dist/templates/server.js.map +1 -1
  79. package/dist/templates/shared.d.ts +4 -4
  80. package/dist/templates/shared.d.ts.map +1 -1
  81. package/dist/templates/shared.js +6 -6
  82. package/dist/templates/shared.js.map +1 -1
  83. package/dist/templates/testing.js +1 -1
  84. package/dist/templates/todos.js +6 -6
  85. package/package.json +4 -4
  86. package/skills/app-structure/SKILL.md +13 -8
  87. package/src/choices.ts +38 -88
  88. package/src/config.ts +2 -2
  89. package/src/create-prompts.ts +20 -21
  90. package/src/create.ts +54 -36
  91. package/src/index.ts +193 -65
  92. package/src/inspect.ts +116 -18
  93. package/src/lib.ts +1 -1
  94. package/src/lint.ts +35 -4
  95. package/src/make/inbox.ts +10 -10
  96. package/src/make/payments.ts +26 -18
  97. package/src/make/shared.ts +72 -50
  98. package/src/make/tenancy.ts +8 -8
  99. package/src/make.ts +607 -191
  100. package/src/mcp.ts +20 -13
  101. package/src/operational-error-reporting.ts +60 -0
  102. package/src/outbox.ts +77 -0
  103. package/src/provider-add.ts +179 -95
  104. package/src/provider-audit.ts +3 -3
  105. package/src/schedule.ts +32 -1
  106. package/src/task.ts +42 -5
  107. package/src/templates/base.ts +16 -16
  108. package/src/templates/index.ts +8 -8
  109. package/src/templates/server.ts +22 -18
  110. package/src/templates/shared.ts +10 -10
  111. package/src/templates/testing.ts +1 -1
  112. package/src/templates/todos.ts +6 -6
  113. package/src/test-helpers/generated-app.ts +1 -0
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { realpathSync } from "node:fs";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { buildApplication, buildCommand, buildRouteMap, proposeCompletions, run, text_en, } from "@stricli/core";
5
- import { completionShellChoices, createIntegrationChoices, databaseChoices, databaseStartCommand, makeFeatureAddonChoices, makeFeatureRecipeChoices, packageManagerChoices, providerPresetChoices, splitCreateIntegrations, templateChoices, } from "./choices.js";
5
+ import { completionShellChoices, createProviderChoices, databaseChoices, databaseStartCommand, makeFeatureAddonChoices, makeFeatureRecipeChoices, packageManagerChoices, providerPresetChoices, splitCreateProviders, templateChoices, } from "./choices.js";
6
6
  import { getCliVersion } from "./version.js";
7
7
  const outputFormatChoices = [
8
8
  "human",
@@ -50,11 +50,17 @@ const parseDate = (input) => {
50
50
  }
51
51
  return value;
52
52
  };
53
- const forceFlag = {
53
+ const createForceFlag = {
54
54
  kind: "boolean",
55
55
  optional: true,
56
56
  withNegated: false,
57
- brief: "Overwrite conflicting files or write into a non-empty directory.",
57
+ brief: "Create the app in a non-empty directory and overwrite conflicts.",
58
+ };
59
+ const makeForceFlag = {
60
+ kind: "boolean",
61
+ optional: true,
62
+ withNegated: false,
63
+ brief: "Overwrite conflicting generated files.",
58
64
  };
59
65
  const dryRunFlag = {
60
66
  kind: "boolean",
@@ -86,7 +92,7 @@ const parsedDateFlag = (brief) => ({
86
92
  optional: true,
87
93
  brief,
88
94
  });
89
- const cwdFlag = parsedStringFlag("App directory to inspect. Defaults to the current working directory.");
95
+ const cwdFlag = parsedStringFlag("App directory. Defaults to the current working directory.");
90
96
  const formatFlag = {
91
97
  kind: "enum",
92
98
  values: outputFormatChoices,
@@ -94,9 +100,10 @@ const formatFlag = {
94
100
  brief: "Output format. Defaults to human, or github when GITHUB_ACTIONS=true.",
95
101
  };
96
102
  const makeFlagParameters = {
97
- force: forceFlag,
103
+ force: makeForceFlag,
98
104
  dryRun: dryRunFlag,
99
105
  json: jsonFlag,
106
+ cwd: cwdFlag,
100
107
  };
101
108
  const routesFlagParameters = {
102
109
  json: jsonFlag,
@@ -119,6 +126,7 @@ const providerAddFlagParameters = {
119
126
  const dbFlagParameters = {
120
127
  json: jsonFlag,
121
128
  dryRun: dryRunFlag,
129
+ cwd: cwdFlag,
122
130
  };
123
131
  const dbSchemaSyncFlagParameters = {
124
132
  ...dbFlagParameters,
@@ -142,6 +150,7 @@ const taskRunFlagParameters = {
142
150
  input: parsedStringFlag("JSON input passed to the task schema."),
143
151
  tenant: parsedStringFlag("Tenant id or slug passed to the app's createTaskContext, separate from task input."),
144
152
  module: parsedStringFlag("Task registry module. Defaults to server/tasks.ts."),
153
+ cwd: cwdFlag,
145
154
  };
146
155
  const outboxDrainFlagParameters = {
147
156
  json: jsonFlag,
@@ -152,6 +161,7 @@ const outboxDrainFlagParameters = {
152
161
  optional: true,
153
162
  brief: "Maximum messages to claim in one drain pass.",
154
163
  },
164
+ cwd: cwdFlag,
155
165
  };
156
166
  const outboxListFlagParameters = {
157
167
  json: jsonFlag,
@@ -175,10 +185,12 @@ const outboxListFlagParameters = {
175
185
  optional: true,
176
186
  brief: "Maximum messages to return. Defaults to 50.",
177
187
  },
188
+ cwd: cwdFlag,
178
189
  };
179
190
  const outboxShowFlagParameters = {
180
191
  json: jsonFlag,
181
192
  module: parsedStringFlag("Outbox registry module. Defaults to server/outbox.ts."),
193
+ cwd: cwdFlag,
182
194
  };
183
195
  const outboxRequeueFlagParameters = {
184
196
  json: jsonFlag,
@@ -190,6 +202,7 @@ const outboxRequeueFlagParameters = {
190
202
  withNegated: false,
191
203
  brief: "Reset attempts to zero before requeueing.",
192
204
  },
205
+ cwd: cwdFlag,
193
206
  };
194
207
  const outboxPurgeFlagParameters = {
195
208
  json: jsonFlag,
@@ -208,6 +221,7 @@ const outboxPurgeFlagParameters = {
208
221
  brief: "Maximum messages to purge.",
209
222
  },
210
223
  dryRun: operationDryRunFlag,
224
+ cwd: cwdFlag,
211
225
  };
212
226
  const outboxPruneFlagParameters = {
213
227
  json: jsonFlag,
@@ -220,12 +234,13 @@ const outboxPruneFlagParameters = {
220
234
  brief: "Maximum messages to prune.",
221
235
  },
222
236
  dryRun: operationDryRunFlag,
237
+ cwd: cwdFlag,
223
238
  };
224
239
  const scheduleRunFlagParameters = {
225
240
  json: jsonFlag,
226
241
  module: parsedStringFlag("Schedule registry module. Defaults to server/schedules.ts."),
227
242
  payload: parsedStringFlag("JSON payload passed to the schedule schema."),
228
- id: parsedStringFlag("Provider or app schedule run ID."),
243
+ runId: parsedStringFlag("Provider or app schedule run ID."),
229
244
  attempt: {
230
245
  kind: "parsed",
231
246
  parse: parsePositiveInteger,
@@ -235,6 +250,7 @@ const scheduleRunFlagParameters = {
235
250
  scheduledAt: parsedStringFlag("Provider scheduled timestamp."),
236
251
  triggeredAt: parsedStringFlag("Schedule trigger timestamp."),
237
252
  source: parsedStringFlag("Provider or app source label."),
253
+ cwd: cwdFlag,
238
254
  };
239
255
  const namePositional = {
240
256
  kind: "tuple",
@@ -289,11 +305,11 @@ and a shadcn UI shell. Pass --api for an API-only scaffold without the
289
305
  UI shell, and --db to choose the database.
290
306
 
291
307
  Available databases: ${databaseChoices.join(", ")}
292
- Available integrations: ${createIntegrationChoices.join(", ")}
308
+ Available providers: ${createProviderChoices.join(", ")}
293
309
 
294
- --integrations accepts the starter template integrations plus the full
295
- beignet providers add preset catalog; presets are applied to the scaffold
296
- with the same machinery as beignet providers add.
310
+ --providers accepts the full beignet provider add preset catalog. Providers
311
+ with starter-native setup are rendered directly; the rest use the same
312
+ machinery as beignet provider add.
297
313
 
298
314
  Running create on an interactive terminal without selection flags opens a
299
315
  prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
@@ -324,12 +340,12 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
324
340
  optional: true,
325
341
  brief: "Package manager to use in next-step commands.",
326
342
  },
327
- integrations: {
343
+ providers: {
328
344
  kind: "enum",
329
- values: createIntegrationChoices,
345
+ values: createProviderChoices,
330
346
  optional: true,
331
347
  variadic: ",",
332
- brief: "Add first-party integrations or provider presets as a comma-separated list.",
348
+ brief: "Add provider presets as a comma-separated list.",
333
349
  },
334
350
  yes: {
335
351
  kind: "boolean",
@@ -337,7 +353,7 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
337
353
  withNegated: false,
338
354
  brief: "Skip interactive prompts and use the defaults.",
339
355
  },
340
- force: forceFlag,
356
+ force: createForceFlag,
341
357
  dryRun: dryRunFlag,
342
358
  json: jsonFlag,
343
359
  },
@@ -354,14 +370,14 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
354
370
  },
355
371
  },
356
372
  loader: async () => {
357
- const { createProject } = await import("./create.js");
373
+ const { createProject, planCreateProject } = await import("./create.js");
358
374
  const { promptCreateSelections, shouldPromptInteractively } = await import("./create-prompts.js");
359
375
  return async function runCreate(flags, directory) {
360
376
  let selections = {
361
377
  directory,
362
378
  api: flags.api,
363
379
  db: flags.db,
364
- integrations: flags.integrations,
380
+ providers: flags.providers,
365
381
  packageManager: flags.packageManager,
366
382
  };
367
383
  const interactive = shouldPromptInteractively({ ...selections, yes: flags.yes }, {
@@ -382,34 +398,65 @@ prompt-based setup. Pass --yes or any selection flag to skip the prompts.`,
382
398
  }
383
399
  const api = selections.api ?? false;
384
400
  const database = selections.db ?? "sqlite";
385
- const { integrations, presets } = splitCreateIntegrations(uniqueValues([...(selections.integrations ?? [])]));
401
+ const { starterProviders, presets } = splitCreateProviders(uniqueValues([...(selections.providers ?? [])]));
386
402
  let presetsNeedEnv = false;
387
403
  if (presets.length > 0) {
388
404
  const { assertCompatibleCreatePresets, providerPresetNeedsEnv } = await import("./provider-add.js");
389
- assertCompatibleCreatePresets(presets, integrations);
405
+ assertCompatibleCreatePresets(presets, starterProviders);
390
406
  presetsNeedEnv = presets.some(providerPresetNeedsEnv);
391
407
  }
392
- const result = await createProject({
408
+ const createOptions = {
393
409
  name: selections.directory,
394
410
  template: flags.template,
395
411
  api,
396
412
  packageManager: selections.packageManager,
397
- integrations,
413
+ providers: starterProviders,
398
414
  db: database,
399
415
  force: Boolean(flags.force),
400
416
  dryRun: Boolean(flags.dryRun),
401
- });
417
+ };
418
+ let result;
419
+ if (flags.dryRun) {
420
+ const plan = await planCreateProject(createOptions);
421
+ if (presets.length === 0) {
422
+ result = plan.result;
423
+ }
424
+ else {
425
+ const { planProviderPresetsForCreate } = await import("./provider-add.js");
426
+ const providerPlan = await planProviderPresetsForCreate({
427
+ targetDir: plan.result.targetDir,
428
+ files: plan.files,
429
+ names: presets,
430
+ });
431
+ result = {
432
+ ...plan.result,
433
+ files: providerPlan.files.map((file) => file.path),
434
+ };
435
+ }
436
+ }
437
+ else {
438
+ result = await createProject(createOptions);
439
+ }
402
440
  if (!flags.dryRun && presets.length > 0) {
403
441
  const { addProviderPreset } = await import("./provider-add.js");
442
+ const presetFiles = [];
404
443
  for (const preset of presets) {
405
- await addProviderPreset({ name: preset, cwd: result.targetDir });
444
+ const presetResult = await addProviderPreset({
445
+ name: preset,
446
+ cwd: result.targetDir,
447
+ });
448
+ presetFiles.push(...presetResult.files);
406
449
  }
450
+ result = {
451
+ ...result,
452
+ files: uniqueValues([...result.files, ...presetFiles]),
453
+ };
407
454
  }
408
455
  writeOutput(this, flags.json
409
- ? JSON.stringify({ ...result, providerPresets: presets }, null, 2)
456
+ ? JSON.stringify({ ...result, providers: selections.providers ?? [] }, null, 2)
410
457
  : nextSteps(result, {
411
458
  api,
412
- integrations,
459
+ providers: starterProviders,
413
460
  database,
414
461
  presets,
415
462
  presetsNeedEnv,
@@ -679,6 +726,7 @@ function databaseCommand(command) {
679
726
  return async function runDb(flags) {
680
727
  const result = await runDatabaseCommand({
681
728
  command,
729
+ cwd: flags.cwd,
682
730
  captureOutput: Boolean(flags.json),
683
731
  dryRun: Boolean(flags.dryRun),
684
732
  });
@@ -704,6 +752,7 @@ const dbSchemaSyncCommand = buildCommand({
704
752
  const { syncDatabaseSchema } = await import("./db.js");
705
753
  return async function runDbSchemaSync(flags) {
706
754
  const result = await syncDatabaseSchema({
755
+ cwd: flags.cwd,
707
756
  dialect: flags.dialect,
708
757
  tables: flags.tables,
709
758
  output: flags.output,
@@ -748,6 +797,7 @@ const taskRunCommand = buildCommand({
748
797
  return async function runTask(flags, name) {
749
798
  const result = await runAppTask({
750
799
  name,
800
+ cwd: flags.cwd,
751
801
  input: flags.input,
752
802
  tenant: flags.tenant,
753
803
  modulePath: flags.module,
@@ -777,6 +827,7 @@ const outboxDrainCommand = buildCommand({
777
827
  const { runOutboxDrain } = await import("./outbox.js");
778
828
  return async function runDrain(flags) {
779
829
  const result = await runOutboxDrain({
830
+ cwd: flags.cwd,
780
831
  modulePath: flags.module,
781
832
  batchSize: flags.batchSize,
782
833
  });
@@ -797,6 +848,7 @@ const outboxListCommand = buildCommand({
797
848
  const { runOutboxList } = await import("./outbox.js");
798
849
  return async function runList(flags) {
799
850
  const result = await runOutboxList({
851
+ cwd: flags.cwd,
800
852
  modulePath: flags.module,
801
853
  status: flags.status,
802
854
  kind: flags.kind,
@@ -821,6 +873,7 @@ const outboxShowCommand = buildCommand({
821
873
  const { runOutboxShow } = await import("./outbox.js");
822
874
  return async function runShow(flags, id) {
823
875
  const result = await runOutboxShow({
876
+ cwd: flags.cwd,
824
877
  modulePath: flags.module,
825
878
  id,
826
879
  });
@@ -842,6 +895,7 @@ const outboxRequeueCommand = buildCommand({
842
895
  const { runOutboxRequeue } = await import("./outbox.js");
843
896
  return async function runRequeue(flags, id) {
844
897
  const result = await runOutboxRequeue({
898
+ cwd: flags.cwd,
845
899
  modulePath: flags.module,
846
900
  id,
847
901
  availableAt: flags.availableAt,
@@ -864,6 +918,7 @@ const outboxPurgeCommand = buildCommand({
864
918
  const { runOutboxPurge } = await import("./outbox.js");
865
919
  return async function runPurge(flags) {
866
920
  const result = await runOutboxPurge({
921
+ cwd: flags.cwd,
867
922
  modulePath: flags.module,
868
923
  before: flags.before,
869
924
  all: Boolean(flags.all),
@@ -890,6 +945,7 @@ const outboxPruneCommand = buildCommand({
890
945
  throw new Error("Pass --before <date> to prune delivered messages.");
891
946
  }
892
947
  const result = await runOutboxPrune({
948
+ cwd: flags.cwd,
893
949
  modulePath: flags.module,
894
950
  before: flags.before,
895
951
  limit: flags.limit,
@@ -927,9 +983,10 @@ const scheduleRunCommand = buildCommand({
927
983
  return async function runSchedule(flags, name) {
928
984
  const result = await runAppSchedule({
929
985
  name,
986
+ cwd: flags.cwd,
930
987
  modulePath: flags.module,
931
988
  payload: flags.payload,
932
- id: flags.id,
989
+ id: flags.runId,
933
990
  attempt: flags.attempt,
934
991
  scheduledAt: flags.scheduledAt,
935
992
  triggeredAt: flags.triggeredAt,
@@ -1012,13 +1069,13 @@ const makeResourceCommand = buildCommand({
1012
1069
  parameters: {
1013
1070
  flags: {
1014
1071
  ...makeFlagParameters,
1015
- auth: {
1072
+ authorization: {
1016
1073
  kind: "boolean",
1017
1074
  optional: true,
1018
1075
  withNegated: false,
1019
1076
  brief: "Generate policy metadata and use-case authorization checks for mutating routes.",
1020
1077
  },
1021
- tenant: {
1078
+ tenantScoped: {
1022
1079
  kind: "boolean",
1023
1080
  optional: true,
1024
1081
  withNegated: false,
@@ -1044,10 +1101,11 @@ const makeResourceCommand = buildCommand({
1044
1101
  return async function runMakeResource(flags, name) {
1045
1102
  const result = await makeResource({
1046
1103
  name,
1104
+ cwd: flags.cwd,
1047
1105
  force: Boolean(flags.force),
1048
1106
  dryRun: Boolean(flags.dryRun),
1049
- auth: Boolean(flags.auth),
1050
- tenant: Boolean(flags.tenant),
1107
+ authorization: Boolean(flags.authorization),
1108
+ tenantScoped: Boolean(flags.tenantScoped),
1051
1109
  events: Boolean(flags.events),
1052
1110
  softDelete: Boolean(flags.softDelete),
1053
1111
  });
@@ -1069,7 +1127,7 @@ const makeFeatureCommand = buildCommand({
1069
1127
  values: makeFeatureAddonChoices,
1070
1128
  optional: true,
1071
1129
  variadic: ",",
1072
- brief: "Add feature-owned artifacts. Supports policy, factory/factories, seed/seeds, task/tasks, event/events, listener/listeners, job/jobs, notification/notifications, schedule/schedules, ui, and upload/uploads.",
1130
+ brief: "Add feature-owned artifacts. Supports policy, factory, seed, task, event, listener, job, notification, schedule, ui, and upload.",
1073
1131
  },
1074
1132
  recipe: {
1075
1133
  kind: "enum",
@@ -1085,6 +1143,7 @@ const makeFeatureCommand = buildCommand({
1085
1143
  return async function runMakeFeature(flags, name) {
1086
1144
  const result = await makeFeature({
1087
1145
  name,
1146
+ cwd: flags.cwd,
1088
1147
  with: flags.with,
1089
1148
  recipe: flags.recipe,
1090
1149
  force: Boolean(flags.force),
@@ -1110,6 +1169,7 @@ function simpleMakeCommand(generator, brief, formatNextSteps) {
1110
1169
  return async function runMake(flags, name) {
1111
1170
  const result = await generators[generator]({
1112
1171
  name,
1172
+ cwd: flags.cwd,
1113
1173
  force: Boolean(flags.force),
1114
1174
  dryRun: Boolean(flags.dryRun),
1115
1175
  });
@@ -1120,6 +1180,38 @@ function simpleMakeCommand(generator, brief, formatNextSteps) {
1120
1180
  },
1121
1181
  });
1122
1182
  }
1183
+ const makeUploadCommand = buildCommand({
1184
+ docs: {
1185
+ brief: "Generate a feature upload.",
1186
+ },
1187
+ parameters: {
1188
+ flags: {
1189
+ ...makeFlagParameters,
1190
+ ui: {
1191
+ kind: "boolean",
1192
+ optional: true,
1193
+ withNegated: false,
1194
+ brief: "Generate a typed React upload client, uploader component, and component test.",
1195
+ },
1196
+ },
1197
+ positional: namePositional,
1198
+ },
1199
+ loader: async () => {
1200
+ const { makeUpload } = await import("./make.js");
1201
+ return async function runMakeUpload(flags, name) {
1202
+ const result = await makeUpload({
1203
+ name,
1204
+ cwd: flags.cwd,
1205
+ force: Boolean(flags.force),
1206
+ dryRun: Boolean(flags.dryRun),
1207
+ ui: Boolean(flags.ui),
1208
+ });
1209
+ writeOutput(this, flags.json
1210
+ ? JSON.stringify(result, null, 2)
1211
+ : makeUploadNextSteps(result));
1212
+ };
1213
+ },
1214
+ });
1123
1215
  const makeListenerCommand = buildCommand({
1124
1216
  docs: {
1125
1217
  brief: "Generate a feature event listener.",
@@ -1127,7 +1219,7 @@ const makeListenerCommand = buildCommand({
1127
1219
  parameters: {
1128
1220
  flags: {
1129
1221
  ...makeFlagParameters,
1130
- event: parsedStringFlag("Event to listen to, for example posts/published."),
1222
+ event: parsedStringFlag("Event to listen to, for example posts.published."),
1131
1223
  },
1132
1224
  positional: namePositional,
1133
1225
  },
@@ -1135,10 +1227,11 @@ const makeListenerCommand = buildCommand({
1135
1227
  const { makeListener } = await import("./make.js");
1136
1228
  return async function runMakeListener(flags, name) {
1137
1229
  if (!flags.event) {
1138
- throw new Error("beignet make listener requires --event feature/name, for example --event posts/published.");
1230
+ throw new Error("beignet make listener requires --event feature.name, for example --event posts.published.");
1139
1231
  }
1140
1232
  const result = await makeListener({
1141
1233
  name,
1234
+ cwd: flags.cwd,
1142
1235
  event: flags.event,
1143
1236
  force: Boolean(flags.force),
1144
1237
  dryRun: Boolean(flags.dryRun),
@@ -1172,6 +1265,7 @@ const makeScheduleCommand = buildCommand({
1172
1265
  return async function runMakeSchedule(flags, name) {
1173
1266
  const result = await makeSchedule({
1174
1267
  name,
1268
+ cwd: flags.cwd,
1175
1269
  cron: flags.cron,
1176
1270
  timezone: flags.timezone,
1177
1271
  route: Boolean(flags.route),
@@ -1195,6 +1289,7 @@ const makePaymentsCommand = buildCommand({
1195
1289
  const { makePayments, makePaymentsNextStepLines } = await import("./make.js");
1196
1290
  return async function runMakePayments(flags) {
1197
1291
  const result = await makePayments({
1292
+ cwd: flags.cwd,
1198
1293
  force: Boolean(flags.force),
1199
1294
  dryRun: Boolean(flags.dryRun),
1200
1295
  });
@@ -1215,6 +1310,7 @@ const makeTenancyCommand = buildCommand({
1215
1310
  const { makeTenancy, makeTenancyNextStepLines } = await import("./make.js");
1216
1311
  return async function runMakeTenancy(flags) {
1217
1312
  const result = await makeTenancy({
1313
+ cwd: flags.cwd,
1218
1314
  force: Boolean(flags.force),
1219
1315
  dryRun: Boolean(flags.dryRun),
1220
1316
  });
@@ -1235,6 +1331,7 @@ const makeInboxCommand = buildCommand({
1235
1331
  const { makeInbox, makeInboxNextStepLines } = await import("./make.js");
1236
1332
  return async function runMakeInbox(flags) {
1237
1333
  const result = await makeInbox({
1334
+ cwd: flags.cwd,
1238
1335
  force: Boolean(flags.force),
1239
1336
  dryRun: Boolean(flags.dryRun),
1240
1337
  });
@@ -1255,6 +1352,7 @@ const makeOutboxCommand = buildCommand({
1255
1352
  const { makeOutbox } = await import("./make.js");
1256
1353
  return async function runMakeOutbox(flags) {
1257
1354
  const result = await makeOutbox({
1355
+ cwd: flags.cwd,
1258
1356
  force: Boolean(flags.force),
1259
1357
  dryRun: Boolean(flags.dryRun),
1260
1358
  });
@@ -1288,7 +1386,7 @@ const makeRoutes = buildRouteMap({
1288
1386
  task: simpleMakeCommand("makeTask", "Generate a feature operational task.", makeTaskNextSteps),
1289
1387
  tenancy: makeTenancyCommand,
1290
1388
  test: simpleMakeCommand("makeTest", "Generate a use case test.", makeTestNextSteps),
1291
- upload: simpleMakeCommand("makeUpload", "Generate a feature upload.", makeUploadNextSteps),
1389
+ upload: makeUploadCommand,
1292
1390
  useCase: simpleMakeCommand("makeUseCase", "Generate a use case.", makeUseCaseNextSteps),
1293
1391
  },
1294
1392
  });
@@ -1310,15 +1408,11 @@ Run npm create beignet@latest (or bun create beignet) to scaffold a new app.`,
1310
1408
  mcp: mcpCommand,
1311
1409
  outbox: outboxRoutes,
1312
1410
  preflight: preflightCommand,
1313
- providers: providerRoutes,
1411
+ provider: providerRoutes,
1314
1412
  routes: routesCommand,
1315
1413
  schedule: scheduleRoutes,
1316
1414
  task: taskRoutes,
1317
1415
  },
1318
- aliases: {
1319
- // The singular form is a common near-miss for the providers commands.
1320
- provider: "providers",
1321
- },
1322
1416
  });
1323
1417
  const cli = buildApplication(rootRoutes, {
1324
1418
  name: "beignet",
@@ -1433,7 +1527,7 @@ function nextSteps(result, options = {}) {
1433
1527
  if (result.dryRun) {
1434
1528
  const plannedFiles = result.files.map((file) => ` ${file}`).join("\n");
1435
1529
  const plannedPresets = options.presets && options.presets.length > 0
1436
- ? `\n\nProvider presets applied after scaffold (skipped in dry run):\n${options.presets
1530
+ ? `\n\nProvider presets included in this plan:\n${options.presets
1437
1531
  .map((preset) => ` ${preset}`)
1438
1532
  .join("\n")}`
1439
1533
  : "";
@@ -1445,14 +1539,14 @@ ${plannedFiles}${plannedPresets}`;
1445
1539
  const pm = result.packageManager;
1446
1540
  const run = pm === "npm" ? "npm run" : `${pm} run`;
1447
1541
  const cli = packageRunnerFromPackageManager(pm);
1448
- const envRequiredIntegrations = options.integrations?.filter(isEnvRequiredProviderIntegration) ?? [];
1449
- const envStep = envRequiredIntegrations.length > 0 || options.presetsNeedEnv
1450
- ? " Fill .env.local for selected provider integrations before starting the app.\n"
1542
+ const envRequiredProviders = options.providers?.filter(isEnvRequiredStarterProvider) ?? [];
1543
+ const envStep = envRequiredProviders.length > 0 || options.presetsNeedEnv
1544
+ ? " Fill .env.local for selected providers before starting the app.\n"
1451
1545
  : "";
1452
1546
  const presetSection = options.presets && options.presets.length > 0
1453
1547
  ? `\nProvider presets applied:\n${options.presets
1454
1548
  .map((preset) => ` ${preset}`)
1455
- .join("\n")}\n See docs/integrations.md for setup notes and follow-up steps.\n`
1549
+ .join("\n")}\n See docs/providers.md for setup notes and follow-up steps.\n`
1456
1550
  : "";
1457
1551
  const openStep = options.api
1458
1552
  ? " open http://localhost:3000 for the API landing page"
@@ -1502,10 +1596,10 @@ function packageRunnerFromPackageManager(pm) {
1502
1596
  return "bun beignet";
1503
1597
  }
1504
1598
  }
1505
- function isEnvRequiredProviderIntegration(integration) {
1506
- return (integration === "inngest" ||
1507
- integration === "resend" ||
1508
- integration === "upstash-rate-limit");
1599
+ function isEnvRequiredStarterProvider(provider) {
1600
+ return (provider === "jobs-inngest" ||
1601
+ provider === "mail-resend" ||
1602
+ provider === "rate-limit-upstash");
1509
1603
  }
1510
1604
  function changedFileLines(result) {
1511
1605
  return {
@@ -1676,8 +1770,16 @@ function makeScheduleNextSteps(result, options = {}) {
1676
1770
  ]);
1677
1771
  }
1678
1772
  function makeUploadNextSteps(result) {
1773
+ const includesUi = result.files.some((file) => file.endsWith("-uploader.tsx"));
1679
1774
  return makeNextSteps(result, "upload", [
1680
1775
  "Replace the starter metadata, constraints, key, authorization, and onComplete behavior.",
1776
+ ...(includesUi
1777
+ ? [
1778
+ "Render the generated uploader with its required resourceId and connect onComplete to refresh the owning view.",
1779
+ ]
1780
+ : [
1781
+ "Add --ui in a full-stack app when you want a typed upload client, component, and component test.",
1782
+ ]),
1681
1783
  "Use the generated upload route for local development, then swap the local storage provider for S3-compatible storage before production.",
1682
1784
  ]);
1683
1785
  }