@percepta/create 4.1.12 → 4.1.13

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/dist/index.js CHANGED
@@ -171,7 +171,7 @@ async function writeManifest(dir, manifest) {
171
171
  async function manifestExists(dir) {
172
172
  return fs.pathExists(getManifestPath(dir));
173
173
  }
174
- function derivePlaceholders(appName, appTitle, repoName = appName, customerSlug = repoName, designTheme = DEFAULT_MOSAIC_DESIGN_THEME) {
174
+ function derivePlaceholders(appName, appTitle, repoName = appName, customerSlug = repoName, designTheme = DEFAULT_MOSAIC_DESIGN_THEME, authMode = "username-password") {
175
175
  const nameSnake = appName.replace(/-/g, "_");
176
176
  const repoNameSnake = repoName.replace(/-/g, "_");
177
177
  return {
@@ -183,7 +183,8 @@ function derivePlaceholders(appName, appTitle, repoName = appName, customerSlug
183
183
  __REPO_NAME__: repoName,
184
184
  __REPO_NAME_SNAKE__: repoNameSnake,
185
185
  __CUSTOMER_SLUG__: customerSlug,
186
- __MOSAIC_DESIGN_THEME__: designTheme
186
+ __MOSAIC_DESIGN_THEME__: designTheme,
187
+ __AUTH_MODE__: authMode
187
188
  };
188
189
  }
189
190
  function resolveMosaicRepoPath(options) {
@@ -225,6 +226,14 @@ const VALID_PROJECT_TYPES = [
225
226
  "webapp",
226
227
  "library"
227
228
  ];
229
+ const VALID_AUTH_MODES = [
230
+ "username-password",
231
+ "google",
232
+ "okta"
233
+ ];
234
+ function isValidAuthMode(value) {
235
+ return typeof value === "string" && VALID_AUTH_MODES.includes(value);
236
+ }
228
237
  function isValidProjectType(value) {
229
238
  return typeof value === "string" && VALID_PROJECT_TYPES.includes(value);
230
239
  }
@@ -280,9 +289,71 @@ async function resolveDesignTheme(projectType, defaults) {
280
289
  if (defaults.projectType && defaults.name) return DEFAULT_MOSAIC_DESIGN_THEME;
281
290
  return promptDesignTheme();
282
291
  }
292
+ async function promptWorkspaceAuthMode() {
293
+ const { authMode } = await inquirer.prompt([{
294
+ type: "rawlist",
295
+ name: "authMode",
296
+ message: "Workspace auth setup?",
297
+ default: "username-password",
298
+ choices: [
299
+ {
300
+ name: "Username/password — local Better Auth credentials",
301
+ value: "username-password"
302
+ },
303
+ {
304
+ name: "Google — Google OAuth via Better Auth",
305
+ value: "google"
306
+ },
307
+ {
308
+ name: "Okta — Okta OIDC via Better Auth",
309
+ value: "okta"
310
+ }
311
+ ]
312
+ }]);
313
+ return authMode;
314
+ }
315
+ async function promptAppAuthMode(defaultAuthMode) {
316
+ const overrideChoices = [
317
+ {
318
+ name: "Username/password — local Better Auth credentials",
319
+ value: "username-password"
320
+ },
321
+ {
322
+ name: "Google — Google OAuth via Better Auth",
323
+ value: "google"
324
+ },
325
+ {
326
+ name: "Okta — Okta OIDC via Better Auth",
327
+ value: "okta"
328
+ }
329
+ ].filter((choice) => choice.value !== defaultAuthMode);
330
+ const { authMode } = await inquirer.prompt([{
331
+ type: "rawlist",
332
+ name: "authMode",
333
+ message: "App auth setup?",
334
+ default: defaultAuthMode,
335
+ choices: [{
336
+ name: "Use workspace default",
337
+ value: defaultAuthMode
338
+ }, ...overrideChoices]
339
+ }]);
340
+ return authMode;
341
+ }
342
+ async function resolveWorkspaceAuthMode(defaults) {
343
+ if (defaults.authMode) return defaults.authMode;
344
+ if (defaults.projectType && defaults.name) return "username-password";
345
+ return promptWorkspaceAuthMode();
346
+ }
347
+ async function resolvePackageAuthMode(projectType, defaults) {
348
+ if (projectType !== "webapp") return void 0;
349
+ if (defaults.authMode) return defaults.authMode;
350
+ const workspaceAuthMode = defaults.workspaceAuthMode ?? "username-password";
351
+ if (defaults.projectType && defaults.name) return workspaceAuthMode;
352
+ return promptAppAuthMode(workspaceAuthMode);
353
+ }
283
354
  /**
284
- * Outside a monorepo we collect the repo name first, then ask a single
285
- * "is it a webapp?" Y/n. Yes (default) → monorepo + webapp, no → bare
355
+ * Outside a monorepo we collect monorepo-level settings first, then ask a
356
+ * single "is it a webapp?" Y/n. Yes (default) → monorepo + webapp, no → bare
286
357
  * monorepo. Library at the top level is rare enough that we leave it as a
287
358
  * `--type library` flag rather than a third prompt option. The repo name is
288
359
  * collected separately from any initial package name so a customer monorepo
@@ -330,6 +401,7 @@ async function promptProjectDetails(defaults) {
330
401
  const customerSlug = await resolveCustomerSlug(defaults);
331
402
  const repoName = defaults.repoName || (defaults.projectType === "monorepo" ? defaults.name : void 0) || await promptName("Repo name?", `${customerSlug}-os`);
332
403
  const repoTitle = toTitleCase(repoName);
404
+ const authMode = await resolveWorkspaceAuthMode(defaults);
333
405
  projectType = defaults.projectType ?? await promptOutsideMonorepoType();
334
406
  await defaults.beforeNamePrompt?.(projectType);
335
407
  if (projectType === "monorepo") {
@@ -343,6 +415,7 @@ async function promptProjectDetails(defaults) {
343
415
  title: finalTitle,
344
416
  installDeps: !defaults.skipInstall,
345
417
  customerSlug,
418
+ authMode,
346
419
  monorepoName: repoName,
347
420
  monorepoTitle: repoTitle
348
421
  };
@@ -360,12 +433,14 @@ async function promptProjectDetails(defaults) {
360
433
  installDeps: !defaults.skipInstall,
361
434
  customerSlug,
362
435
  designTheme,
436
+ authMode,
363
437
  monorepoName: repoName,
364
438
  monorepoTitle: repoTitle
365
439
  };
366
440
  }
367
441
  const finalTitle = finalName ? toTitleCase(finalName) : "";
368
442
  const designTheme = await resolveDesignTheme(projectType, defaults);
443
+ const authMode = await resolvePackageAuthMode(projectType, defaults);
369
444
  const finalDirectory = !inMonorepo && finalName ? path.resolve(cwd, finalName) : "";
370
445
  return {
371
446
  projectType,
@@ -373,7 +448,8 @@ async function promptProjectDetails(defaults) {
373
448
  name: finalName,
374
449
  title: finalTitle,
375
450
  installDeps: !defaults.skipInstall,
376
- designTheme
451
+ designTheme,
452
+ authMode
377
453
  };
378
454
  }
379
455
  //#endregion
@@ -419,7 +495,9 @@ const PLACEHOLDERS = {
419
495
  __CUSTOMER_SLUG__: "customerSlug",
420
496
  __CREATE_PACKAGE__: "createPackage",
421
497
  __CREATE_VERSION__: "createVersion",
422
- __MOSAIC_DESIGN_THEME__: "designTheme"
498
+ __MOSAIC_DESIGN_THEME__: "designTheme",
499
+ __AUTH_MODE__: "authMode",
500
+ __AUTH_MODE_LABEL__: "authModeLabel"
423
501
  };
424
502
  const SKIP_DIRS = new Set([
425
503
  "node_modules",
@@ -537,11 +615,12 @@ const WORKSPACE_MANIFEST_FILENAME = ".mosaic-workspace.json";
537
615
  function getWorkspaceManifestPath(rootDir) {
538
616
  return path.join(rootDir, WORKSPACE_MANIFEST_FILENAME);
539
617
  }
540
- function createWorkspaceManifest({ customerSlug, createdAt = (/* @__PURE__ */ new Date()).toISOString() }) {
618
+ function createWorkspaceManifest({ customerSlug, authMode, createdAt = (/* @__PURE__ */ new Date()).toISOString() }) {
541
619
  const createPackage = readCreatePackageMetadata();
542
620
  return {
543
621
  schemaVersion: 1,
544
622
  customerSlug,
623
+ authMode,
545
624
  createPackage: createPackage.name,
546
625
  createVersion: createPackage.version,
547
626
  monorepoTemplateVersion: getTemplateVersion("monorepo"),
@@ -552,6 +631,9 @@ function createWorkspaceManifest({ customerSlug, createdAt = (/* @__PURE__ */ ne
552
631
  createdAt
553
632
  };
554
633
  }
634
+ function getWorkspaceAuthMode(manifest) {
635
+ return manifest?.authMode ?? "username-password";
636
+ }
555
637
  async function readWorkspaceManifest(rootDir) {
556
638
  const manifestPath = getWorkspaceManifestPath(rootDir);
557
639
  if (!await fs.pathExists(manifestPath)) return null;
@@ -778,13 +860,13 @@ async function writeMosaicFiles(packageDir, config, projectType, templateVersion
778
860
  templateVersion,
779
861
  templateCommit,
780
862
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
781
- placeholders: derivePlaceholders(config.name, config.title, config.repoName, config.customerSlug, config.designTheme),
863
+ placeholders: derivePlaceholders(config.name, config.title, config.repoName, config.customerSlug, config.designTheme, config.authMode),
782
864
  source: { templatePath: `packages/blueberry/templates/${projectType}` }
783
865
  });
784
866
  const notesPath = path.join(packageDir, "mosaic-template-notes.md");
785
867
  await fs.writeFile(notesPath, `# Mosaic Divergence Notes\n\nDocument intentional differences from the ${projectType} template here.\nClaude reads this file during sync to preserve your customizations.\n\n## Intentional Divergences\n\n_None yet — freshly created from template._\n`);
786
868
  }
787
- function buildAppConfig(name, title = toTitleCase(name), repoName = name, customerSlug = repoName, designTheme = DEFAULT_MOSAIC_DESIGN_THEME) {
869
+ function buildAppConfig(name, title = toTitleCase(name), repoName = name, customerSlug = repoName, designTheme = DEFAULT_MOSAIC_DESIGN_THEME, authMode = "username-password") {
788
870
  const createPackage = readCreatePackageMetadata();
789
871
  return {
790
872
  name,
@@ -797,7 +879,9 @@ function buildAppConfig(name, title = toTitleCase(name), repoName = name, custom
797
879
  customerSlug,
798
880
  createPackage: createPackage.name,
799
881
  createVersion: createPackage.version,
800
- designTheme
882
+ designTheme,
883
+ authMode,
884
+ authModeLabel: getAuthModeLabel(authMode)
801
885
  };
802
886
  }
803
887
  /** Copy the monorepo template into `targetDir` and replace its placeholders. */
@@ -942,8 +1026,9 @@ async function runGeneratedProjectChecks(args) {
942
1026
  * Gated on `installSucceeded` because starting setup without node_modules
943
1027
  * leaves an orphan Docker container.
944
1028
  */
945
- async function maybeAutoRunWebapp(packageDir, monorepoRoot, projectType, installSucceeded) {
1029
+ async function maybeAutoRunWebapp(packageDir, monorepoRoot, projectType, authMode, installSucceeded) {
946
1030
  if (!packageDir || projectType !== "webapp" || !installSucceeded) return false;
1031
+ if (authMode !== "username-password") return false;
947
1032
  return autoRunWebapp(packageDir, monorepoRoot);
948
1033
  }
949
1034
  function getProjectTypeLabel(projectType) {
@@ -954,6 +1039,14 @@ function getProjectTypeLabel(projectType) {
954
1039
  default: throw new Error(`Unknown project type: ${String(projectType)}`);
955
1040
  }
956
1041
  }
1042
+ function getAuthModeLabel(authMode) {
1043
+ switch (authMode) {
1044
+ case "username-password": return "Username/password";
1045
+ case "google": return "Google OAuth";
1046
+ case "okta": return "Okta OIDC";
1047
+ default: throw new Error(`Unknown auth mode: ${String(authMode)}`);
1048
+ }
1049
+ }
957
1050
  function requireNpmTokenForWebappInstall(projectType, installDeps) {
958
1051
  if (projectType !== "webapp" || !installDeps || process.env.NPM_TOKEN) return;
959
1052
  console.log();
@@ -996,6 +1089,10 @@ async function createProject(options) {
996
1089
  console.error(chalk.red(`Error: Invalid design theme "${options.theme}". Valid themes are: ${VALID_MOSAIC_DESIGN_THEMES.join(", ")}`));
997
1090
  process.exit(1);
998
1091
  }
1092
+ if (options.auth !== void 0 && !isValidAuthMode(options.auth)) {
1093
+ console.error(chalk.red(`Error: Invalid auth setup "${options.auth}". Valid auth setups are: ${VALID_AUTH_MODES.join(", ")}`));
1094
+ process.exit(1);
1095
+ }
999
1096
  console.log();
1000
1097
  console.log(chalk.bold("Creating a new Mosaic package..."));
1001
1098
  console.log();
@@ -1012,8 +1109,10 @@ async function createProject(options) {
1012
1109
  else console.log(chalk.dim(" No monorepo detected. A new monorepo will be created."));
1013
1110
  console.log();
1014
1111
  const workspaceManifest = monorepoContext.found ? await readWorkspaceManifest(monorepoContext.rootDir) : null;
1112
+ const workspaceAuthMode = getWorkspaceAuthMode(workspaceManifest);
1015
1113
  if (workspaceManifest) {
1016
1114
  console.log(chalk.dim(" Workspace create version:"), chalk.cyan(`${workspaceManifest.createPackage}@${workspaceManifest.createVersion}`));
1115
+ console.log(chalk.dim(" Workspace auth setup:"), chalk.cyan(getAuthModeLabel(workspaceAuthMode)));
1017
1116
  console.log();
1018
1117
  } else if (monorepoContext.found) {
1019
1118
  console.log(chalk.yellow("!"), "No .mosaic-workspace.json found; using this CLI's bundled templates.");
@@ -1062,6 +1161,7 @@ async function createProject(options) {
1062
1161
  installDeps: !options.skipInstall,
1063
1162
  customerSlug: monorepoContext.found ? void 0 : customerSlug ?? kebabRepoName,
1064
1163
  designTheme: projectType === "webapp" ? options.theme ?? "modern" : void 0,
1164
+ authMode: options.auth ?? (monorepoContext.found ? workspaceAuthMode : "username-password"),
1065
1165
  monorepoName: monorepoContext.found ? void 0 : kebabRepoName,
1066
1166
  monorepoTitle: monorepoContext.found ? void 0 : toTitleCase(kebabRepoName)
1067
1167
  };
@@ -1071,6 +1171,8 @@ async function createProject(options) {
1071
1171
  name: projectName ? toKebabCase(projectName) : void 0,
1072
1172
  customerSlug,
1073
1173
  designTheme: options.theme,
1174
+ authMode: options.auth,
1175
+ workspaceAuthMode: monorepoContext.found ? workspaceAuthMode : void 0,
1074
1176
  repoName: repoName ? toKebabCase(repoName) : void 0,
1075
1177
  skipInstall: options.skipInstall,
1076
1178
  monorepoContext,
@@ -1082,13 +1184,15 @@ async function createProject(options) {
1082
1184
  });
1083
1185
  if (monorepoContext.found && monorepoContext.packageDir && !answers.directory) answers.directory = path.join(monorepoContext.packageDir, answers.name);
1084
1186
  }
1187
+ const selectedAuthMode = answers.authMode ?? (monorepoContext.found ? workspaceAuthMode : "username-password");
1188
+ answers.authMode = selectedAuthMode;
1085
1189
  const monorepoName = answers.monorepoName ?? answers.name;
1086
1190
  const monorepoTitle = answers.monorepoTitle ?? toTitleCase(monorepoName);
1087
1191
  const newWorkspaceCustomerSlug = answers.customerSlug ?? monorepoName;
1088
- const monorepoConfig = buildAppConfig(monorepoName, monorepoTitle, monorepoName, newWorkspaceCustomerSlug, DEFAULT_MOSAIC_DESIGN_THEME);
1192
+ const monorepoConfig = buildAppConfig(monorepoName, monorepoTitle, monorepoName, newWorkspaceCustomerSlug, DEFAULT_MOSAIC_DESIGN_THEME, selectedAuthMode);
1089
1193
  const configRepoName = monorepoContext.found ? path.basename(monorepoContext.rootDir) : monorepoName;
1090
1194
  const effectiveCustomerSlug = monorepoContext.found ? workspaceManifest?.customerSlug ?? configRepoName : newWorkspaceCustomerSlug;
1091
- const config = buildAppConfig(answers.name, answers.title, configRepoName, effectiveCustomerSlug, answers.designTheme);
1195
+ const config = buildAppConfig(answers.name, answers.title, configRepoName, effectiveCustomerSlug, answers.designTheme, selectedAuthMode);
1092
1196
  const typeLabel = getProjectTypeLabel(answers.projectType);
1093
1197
  if (monorepoContext.found) {
1094
1198
  const monorepoRoot = monorepoContext.rootDir;
@@ -1100,6 +1204,8 @@ async function createProject(options) {
1100
1204
  if (answers.projectType === "webapp") {
1101
1205
  console.log(chalk.dim(" Database:"), config.dbName);
1102
1206
  console.log(chalk.dim(" Design theme:"), config.designTheme);
1207
+ console.log(chalk.dim(" App auth setup:"), config.authModeLabel);
1208
+ if (selectedAuthMode !== workspaceAuthMode) console.log(chalk.dim(" Workspace auth default:"), getAuthModeLabel(workspaceAuthMode));
1103
1209
  }
1104
1210
  console.log();
1105
1211
  if (await fs.pathExists(packageDir)) {
@@ -1128,7 +1234,7 @@ async function createProject(options) {
1128
1234
  console.log();
1129
1235
  console.log(chalk.green("✔"), chalk.bold(`Created ${typeLabel} at`), chalk.cyan(path.relative(monorepoRoot, packageDir)));
1130
1236
  console.log();
1131
- if (await maybeAutoRunWebapp(packageDir, monorepoRoot, answers.projectType, installSucceeded && checksSucceeded)) return;
1237
+ if (await maybeAutoRunWebapp(packageDir, monorepoRoot, answers.projectType, answers.authMode, installSucceeded && checksSucceeded)) return;
1132
1238
  printNextStepsExisting(answers, packageDir, !installSucceeded);
1133
1239
  } else {
1134
1240
  const isBareMonorepo = answers.projectType === "monorepo";
@@ -1140,11 +1246,13 @@ async function createProject(options) {
1140
1246
  console.log(chalk.dim(" Customer:"), newWorkspaceCustomerSlug);
1141
1247
  console.log(chalk.dim(" Repo name:"), monorepoConfig.name);
1142
1248
  console.log(chalk.dim(" Title:"), monorepoConfig.title);
1249
+ console.log(chalk.dim(" Workspace auth setup:"), monorepoConfig.authModeLabel);
1143
1250
  } else {
1144
1251
  console.log(chalk.dim(" Package type:"), typeLabel);
1145
1252
  console.log(chalk.dim(" Monorepo directory:"), monorepoRoot);
1146
1253
  console.log(chalk.dim(" Customer:"), newWorkspaceCustomerSlug);
1147
1254
  console.log(chalk.dim(" Repo name:"), monorepoConfig.name);
1255
+ console.log(chalk.dim(" Workspace auth setup:"), monorepoConfig.authModeLabel);
1148
1256
  console.log(chalk.dim(" Package:"), `packages/${answers.name}/`);
1149
1257
  console.log(chalk.dim(" Name:"), config.name);
1150
1258
  console.log(chalk.dim(" Title:"), config.title);
@@ -1161,7 +1269,10 @@ async function createProject(options) {
1161
1269
  }
1162
1270
  }
1163
1271
  await scaffoldMonorepo(monorepoRoot, monorepoConfig);
1164
- const newWorkspaceManifest = createWorkspaceManifest({ customerSlug: newWorkspaceCustomerSlug });
1272
+ const newWorkspaceManifest = createWorkspaceManifest({
1273
+ customerSlug: newWorkspaceCustomerSlug,
1274
+ authMode: selectedAuthMode
1275
+ });
1165
1276
  await writeWorkspaceManifest(monorepoRoot, newWorkspaceManifest);
1166
1277
  if (packageDir && answers.projectType !== "monorepo") await addPackageToMonorepo({
1167
1278
  packageDir,
@@ -1184,7 +1295,7 @@ async function createProject(options) {
1184
1295
  console.log(chalk.green("✔"), chalk.bold(isBareMonorepo ? `Created ${typeLabel} at` : "Created monorepo at"), chalk.cyan(monorepoRoot));
1185
1296
  if (!isBareMonorepo) console.log(chalk.green("✔"), chalk.bold(`Created ${typeLabel} at`), chalk.cyan(`packages/${answers.name}/`));
1186
1297
  console.log();
1187
- if (await maybeAutoRunWebapp(packageDir, monorepoRoot, answers.projectType, installSucceeded && checksSucceeded)) return;
1298
+ if (await maybeAutoRunWebapp(packageDir, monorepoRoot, answers.projectType, answers.authMode, installSucceeded && checksSucceeded)) return;
1188
1299
  printNextStepsNew(answers, monorepoRoot, !installSucceeded);
1189
1300
  }
1190
1301
  }
@@ -1209,6 +1320,7 @@ function printWebappNextSteps(params) {
1209
1320
  const pkgFromRoot = shPath(packageRelativePathFromRoot ?? `packages/${answers.name}`) || ".";
1210
1321
  const setupStep = "pnpm run setup";
1211
1322
  const devStep = "pnpm dev";
1323
+ printAuthSetupNotes(answers);
1212
1324
  if (variant === "new") {
1213
1325
  const oneLinerParts = [];
1214
1326
  if (repoRel !== ".") oneLinerParts.push(`cd ${repoRel}`);
@@ -1247,6 +1359,32 @@ function printWebappNextSteps(params) {
1247
1359
  console.log(chalk.dim(` ${step++}.`), `cd ${pkgFromRoot}`);
1248
1360
  console.log(chalk.dim(` ${step++}.`), devStep);
1249
1361
  }
1362
+ function printAuthSetupNotes(answers) {
1363
+ if (!answers.authMode) return;
1364
+ switch (answers.authMode) {
1365
+ case "username-password": return;
1366
+ case "google":
1367
+ console.log();
1368
+ console.log(chalk.bold("Google auth setup:"));
1369
+ console.log(chalk.dim(" Fill in"), chalk.cyan("GOOGLE_CLIENT_ID"), chalk.dim("and"), chalk.cyan("GOOGLE_CLIENT_SECRET"), chalk.dim("in each app environment before OAuth sign-in."));
1370
+ console.log(chalk.dim(" Optional: set"), chalk.cyan("GOOGLE_HOSTED_DOMAIN"), chalk.dim("to hint/restrict the Google Workspace domain."));
1371
+ console.log(chalk.dim(" Register redirect URIs:"), chalk.cyan("http://localhost:3000/api/auth/callback/google"), chalk.dim("and"), chalk.cyan("https://<app-host>/api/auth/callback/google"));
1372
+ console.log(chalk.dim(" Provider users still need SpiceDB app access after sign-in; seed or grant access for their user."));
1373
+ return;
1374
+ case "okta":
1375
+ console.log();
1376
+ console.log(chalk.bold("Okta auth setup:"));
1377
+ console.log(chalk.dim(" Fill in"), chalk.cyan("OKTA_CLIENT_ID"), chalk.dim(","), chalk.cyan("OKTA_CLIENT_SECRET"), chalk.dim("and"), chalk.cyan("OKTA_ISSUER"), chalk.dim("in each app environment before OAuth sign-in."));
1378
+ console.log(chalk.dim(" Example issuer:"), chalk.cyan("https://dev-xxxxx.okta.com/oauth2/default"));
1379
+ console.log(chalk.dim(" Register redirect URIs:"), chalk.cyan("http://localhost:3000/api/auth/oauth2/callback/okta"), chalk.dim("and"), chalk.cyan("https://<app-host>/api/auth/oauth2/callback/okta"));
1380
+ console.log(chalk.dim(" Provider users still need SpiceDB app access after sign-in; seed or grant access for their user."));
1381
+ return;
1382
+ default: {
1383
+ const exhaustiveCheck = answers.authMode;
1384
+ throw new Error(`Unknown auth mode: ${String(exhaustiveCheck)}`);
1385
+ }
1386
+ }
1387
+ }
1250
1388
  async function warnIfMissingRootNpmrc(rootDir) {
1251
1389
  const rootNpmrc = path.join(rootDir, ".npmrc");
1252
1390
  let contents = "";
@@ -1268,6 +1406,7 @@ function printNextStepsNew(answers, targetDir, installNeeded) {
1268
1406
  console.log();
1269
1407
  switch (answers.projectType) {
1270
1408
  case "monorepo": {
1409
+ printAuthSetupNotes(answers);
1271
1410
  let step = 1;
1272
1411
  const repoRel = shPath(relativePath);
1273
1412
  if (repoRel !== ".") console.log(chalk.dim(` ${step++}.`), `cd ${repoRel}`);
@@ -1285,6 +1424,7 @@ function printNextStepsNew(answers, targetDir, installNeeded) {
1285
1424
  });
1286
1425
  break;
1287
1426
  case "library": {
1427
+ printAuthSetupNotes(answers);
1288
1428
  let step = 1;
1289
1429
  const repoRel = shPath(relativePath);
1290
1430
  if (repoRel !== ".") console.log(chalk.dim(` ${step++}.`), `cd ${repoRel}`);
@@ -1342,8 +1482,8 @@ function printNextStepsExisting(answers, packageDir, installNeeded) {
1342
1482
  //#region src/index.ts
1343
1483
  const packageJson = readCreatePackageMetadata();
1344
1484
  program.name("create").description("Scaffold and manage Mosaic packages").version(packageJson.version);
1345
- program.command("create", { isDefault: true }).description("Scaffold a new Mosaic package").option("-t, --type <type>", "Package type: monorepo, webapp, or library").option("--name <name>", "Package/app name").option("--customer <slug>", "Customer slug for the new monorepo").option("--theme <theme>", "Webapp design theme: modern, paper, or dense").option("--repo-name <name>", "Repository name when creating a new monorepo").option("--cwd <dir>", "Run create as if started from this directory").option("--skip-install", "Skip dependency installation (also skips the auto-run setup + dev + browser)", false).option("-y, --yes", "Skip all prompts and use defaults", false).action(createProject);
1346
- program.command("add").description("Add a Mosaic package to the current monorepo").argument("[typeOrName]", "Package type (webapp/library) or package name").argument("[name]", "Package/app name").option("-t, --type <type>", "Package type: webapp or library").option("--name <name>", "Package/app name").option("--theme <theme>", "Webapp design theme: modern, paper, or dense").option("--skip-install", "Skip dependency installation (also skips the auto-run setup + dev + browser)", false).option("-y, --yes", "Skip all prompts and use defaults", false).action(async (typeOrName, name, options) => {
1485
+ program.command("create", { isDefault: true }).description("Scaffold a new Mosaic package").option("-t, --type <type>", "Package type: monorepo, webapp, or library").option("--name <name>", "Package/app name").option("--customer <slug>", "Customer slug for the new monorepo").option("--theme <theme>", "Webapp design theme: modern, paper, or dense").option("--auth <mode>", "Workspace auth setup: username-password, google, or okta").option("--repo-name <name>", "Repository name when creating a new monorepo").option("--cwd <dir>", "Run create as if started from this directory").option("--skip-install", "Skip dependency installation (also skips the auto-run setup + dev + browser)", false).option("-y, --yes", "Skip all prompts and use defaults", false).action(createProject);
1486
+ program.command("add").description("Add a Mosaic package to the current monorepo").argument("[typeOrName]", "Package type (webapp/library) or package name").argument("[name]", "Package/app name").option("-t, --type <type>", "Package type: webapp or library").option("--name <name>", "Package/app name").option("--theme <theme>", "Webapp design theme: modern, paper, or dense").option("--auth <mode>", "App auth setup override: username-password, google, or okta").option("--skip-install", "Skip dependency installation (also skips the auto-run setup + dev + browser)", false).option("-y, --yes", "Skip all prompts and use defaults", false).action(async (typeOrName, name, options) => {
1347
1487
  let projectType = options.type;
1348
1488
  let projectName = options.name;
1349
1489
  if (typeOrName === "webapp" || typeOrName === "library") {