playcademy 0.26.0 → 0.26.1-beta.2

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/cli.js CHANGED
@@ -51,17 +51,17 @@ __export(file_loader_exports, {
51
51
  loadPackageJson: () => loadPackageJson,
52
52
  scanDirectory: () => scanDirectory
53
53
  });
54
- import { existsSync, readdirSync, statSync } from "fs";
54
+ import { existsSync as existsSync3, readdirSync, statSync } from "fs";
55
55
  import { readFile } from "fs/promises";
56
- import { dirname, parse, resolve } from "path";
56
+ import { dirname, parse, resolve as resolve2 } from "path";
57
57
  function findFilePath(filename, startDir, maxLevels = 3) {
58
58
  const filenames = Array.isArray(filename) ? filename : [filename];
59
- let currentDir = resolve(startDir);
59
+ let currentDir = resolve2(startDir);
60
60
  let levelsSearched = 0;
61
61
  while (levelsSearched <= maxLevels) {
62
62
  for (const fname of filenames) {
63
- const filePath = resolve(currentDir, fname);
64
- if (existsSync(filePath)) {
63
+ const filePath = resolve2(currentDir, fname);
64
+ if (existsSync3(filePath)) {
65
65
  return {
66
66
  path: filePath,
67
67
  dir: currentDir,
@@ -101,8 +101,8 @@ async function loadFile(filename, options = {}) {
101
101
  const filenames = Array.isArray(filename) ? filename : [filename];
102
102
  fileResult = null;
103
103
  for (const fname of filenames) {
104
- const filePath = resolve(cwd, fname);
105
- if (existsSync(filePath)) {
104
+ const filePath = resolve2(cwd, fname);
105
+ if (existsSync3(filePath)) {
106
106
  fileResult = {
107
107
  path: filePath,
108
108
  dir: cwd,
@@ -143,8 +143,8 @@ async function findFile(filename, options = {}) {
143
143
  }
144
144
  const filenames = Array.isArray(filename) ? filename : [filename];
145
145
  for (const fname of filenames) {
146
- const filePath = resolve(cwd, fname);
147
- if (existsSync(filePath)) {
146
+ const filePath = resolve2(cwd, fname);
147
+ if (existsSync3(filePath)) {
148
148
  return {
149
149
  path: filePath,
150
150
  dir: cwd,
@@ -205,8 +205,8 @@ async function loadModule(filename, options = {}) {
205
205
  const filenames = Array.isArray(filename) ? filename : [filename];
206
206
  fileResult = null;
207
207
  for (const fname of filenames) {
208
- const filePath = resolve(cwd, fname);
209
- if (existsSync(filePath)) {
208
+ const filePath = resolve2(cwd, fname);
209
+ if (existsSync3(filePath)) {
210
210
  fileResult = {
211
211
  path: filePath,
212
212
  dir: cwd,
@@ -242,7 +242,7 @@ async function loadModule(filename, options = {}) {
242
242
  function scanDirectory(dir, options = {}) {
243
243
  const { extensions, allowMissing = false } = options;
244
244
  const files = [];
245
- if (!existsSync(dir)) {
245
+ if (!existsSync3(dir)) {
246
246
  if (allowMissing) {
247
247
  return [];
248
248
  }
@@ -252,7 +252,7 @@ function scanDirectory(dir, options = {}) {
252
252
  try {
253
253
  const entries = readdirSync(currentDir);
254
254
  for (const entry of entries) {
255
- const fullPath = resolve(currentDir, entry);
255
+ const fullPath = resolve2(currentDir, entry);
256
256
  const relativePath = basePath ? `${basePath}/${entry}` : entry;
257
257
  const stat = statSync(fullPath);
258
258
  if (stat.isDirectory()) {
@@ -270,7 +270,7 @@ function scanDirectory(dir, options = {}) {
270
270
  return files;
271
271
  }
272
272
  function findFilesByExtension(dir, extension) {
273
- if (!existsSync(dir)) {
273
+ if (!existsSync3(dir)) {
274
274
  return [];
275
275
  }
276
276
  const ext = extension.toLowerCase().replace(/^\./, "");
@@ -278,7 +278,7 @@ function findFilesByExtension(dir, extension) {
278
278
  try {
279
279
  const entries = readdirSync(dir);
280
280
  for (const entry of entries) {
281
- const fullPath = resolve(dir, entry);
281
+ const fullPath = resolve2(dir, entry);
282
282
  const stat = statSync(fullPath);
283
283
  if (stat.isFile()) {
284
284
  const fileExt = getFileExtension(entry);
@@ -318,6 +318,134 @@ import {
318
318
  yellowBright
319
319
  } from "colorette";
320
320
  import { colorize } from "json-colorizer";
321
+
322
+ // src/lib/core/context.ts
323
+ import { existsSync as existsSync2 } from "fs";
324
+ import { resolve } from "path";
325
+
326
+ // ../utils/src/package-manager.ts
327
+ import { execSync } from "child_process";
328
+ import { existsSync } from "fs";
329
+ import { join } from "path";
330
+ function isCommandAvailable(command) {
331
+ try {
332
+ execSync(`command -v ${command}`, { stdio: "ignore" });
333
+ return true;
334
+ } catch {
335
+ return false;
336
+ }
337
+ }
338
+ function detectPackageManager(cwd = process.cwd()) {
339
+ if (existsSync(join(cwd, "bun.lock")) || existsSync(join(cwd, "bun.lockb"))) {
340
+ return "bun";
341
+ }
342
+ if (existsSync(join(cwd, "pnpm-lock.yaml"))) {
343
+ return "pnpm";
344
+ }
345
+ if (existsSync(join(cwd, "yarn.lock"))) {
346
+ return "yarn";
347
+ }
348
+ if (existsSync(join(cwd, "package-lock.json"))) {
349
+ return "npm";
350
+ }
351
+ return detectByCommandAvailability();
352
+ }
353
+ function detectByCommandAvailability() {
354
+ if (isCommandAvailable("bun")) {
355
+ return "bun";
356
+ }
357
+ if (isCommandAvailable("pnpm")) {
358
+ return "pnpm";
359
+ }
360
+ if (isCommandAvailable("yarn")) {
361
+ return "yarn";
362
+ }
363
+ return "npm";
364
+ }
365
+ function getInstallCommand(pm) {
366
+ switch (pm) {
367
+ case "bun": {
368
+ return "bun install";
369
+ }
370
+ case "pnpm": {
371
+ return "pnpm install";
372
+ }
373
+ case "yarn": {
374
+ return "yarn install";
375
+ }
376
+ case "npm":
377
+ default: {
378
+ return "npm install";
379
+ }
380
+ }
381
+ }
382
+ function getRunCommand(pm, script) {
383
+ switch (pm) {
384
+ case "bun": {
385
+ return `bun run ${script}`;
386
+ }
387
+ case "pnpm": {
388
+ return `pnpm run ${script}`;
389
+ }
390
+ case "yarn": {
391
+ return `yarn run ${script}`;
392
+ }
393
+ case "npm":
394
+ default: {
395
+ return `npm run ${script}`;
396
+ }
397
+ }
398
+ }
399
+ function getAddDevDependencyCommand(pm, packageName) {
400
+ switch (pm) {
401
+ case "bun": {
402
+ return `bun add -D ${packageName}`;
403
+ }
404
+ case "pnpm": {
405
+ return `pnpm add -D ${packageName}`;
406
+ }
407
+ case "yarn": {
408
+ return `yarn add -D ${packageName}`;
409
+ }
410
+ case "npm":
411
+ default: {
412
+ return `npm install --save-dev ${packageName}`;
413
+ }
414
+ }
415
+ }
416
+
417
+ // src/lib/core/context.ts
418
+ var context = {};
419
+ var cache = {
420
+ packageManager: null
421
+ };
422
+ function setCliContext(ctx) {
423
+ context = { ...context, ...ctx };
424
+ }
425
+ function getCliContext() {
426
+ return context;
427
+ }
428
+ function getWorkspace() {
429
+ return context.workspace || process.cwd();
430
+ }
431
+ function getPackageManager() {
432
+ if (cache.packageManager) {
433
+ return cache.packageManager;
434
+ }
435
+ cache.packageManager = detectPackageManager(getWorkspace());
436
+ return cache.packageManager;
437
+ }
438
+ function hasPackageJson(dir) {
439
+ return existsSync2(resolve(dir || getWorkspace(), "package.json"));
440
+ }
441
+ function isNonInteractive() {
442
+ return process.env.CI === "1" || process.env.CI === "true" || Boolean(context.json);
443
+ }
444
+ function shouldAssumeYes() {
445
+ return Boolean(context.yes);
446
+ }
447
+
448
+ // src/lib/core/logger.ts
321
449
  var lastWasBlank = false;
322
450
  var ANSI_ESCAPE_RE = /\x1b\[[^a-zA-Z]*[a-zA-Z]/g;
323
451
  function hasVisibleContent(str) {
@@ -353,13 +481,25 @@ process.stderr.write = (chunk, ...rest) => {
353
481
  }
354
482
  return result;
355
483
  };
484
+ function isJsonMode() {
485
+ return Boolean(getCliContext().json);
486
+ }
356
487
  function writeOut(line) {
488
+ if (isJsonMode()) {
489
+ return;
490
+ }
491
+ console.log(line);
492
+ }
493
+ function writeRaw(line) {
357
494
  console.log(line);
358
495
  }
359
496
  function writeErr(line) {
360
497
  console.error(line);
361
498
  }
362
499
  function writeBlank() {
500
+ if (isJsonMode()) {
501
+ return;
502
+ }
363
503
  if (lastWasBlank) {
364
504
  return;
365
505
  }
@@ -566,7 +706,11 @@ var logger = {
566
706
  return label ? `${bold(label)} ${transition}` : transition;
567
707
  },
568
708
  /**
569
- * JSON output - pretty-printed JSON
709
+ * Pretty-printed, colorized JSON for humans reading the terminal. Like other
710
+ * human-facing stdout it is suppressed in global `--json` mode so it can't
711
+ * corrupt the single machine object — use `stdout` for that channel. Commands
712
+ * with their own per-command `--json` flag (kv/bucket) never set global
713
+ * `--json` mode, so this still prints for them as before.
570
714
  */
571
715
  json: (data, indent = 0) => {
572
716
  const spaces = " ".repeat(indent);
@@ -582,12 +726,31 @@ var logger = {
582
726
  writeBlank();
583
727
  },
584
728
  /**
585
- * Raw output - no formatting, useful for ASCII art or pre-formatted text
729
+ * Raw human output - no formatting, useful for ASCII art or pre-formatted text.
730
+ * Suppressed in `--json` mode like other human-facing stdout.
586
731
  */
587
732
  raw: (text, indent = 0) => {
588
733
  const spaces = " ".repeat(indent);
589
734
  writeOut(`${spaces}${text}`);
590
735
  },
736
+ /**
737
+ * Intentional stdout payload — use for command results, raw/plain modes,
738
+ * streaming data, or the primary `--json` object. This bypasses `--json`
739
+ * human-output suppression, so callers should use it only for output the
740
+ * caller explicitly requested on stdout.
741
+ */
742
+ stdout: (text, indent = 0) => {
743
+ const spaces = " ".repeat(indent);
744
+ writeRaw(`${spaces}${text}`);
745
+ },
746
+ /**
747
+ * Diagnostic line on stderr — safe to emit alongside `--json` stdout.
748
+ * Use for debug/progress output that must not touch the machine channel.
749
+ */
750
+ errLine: (text, indent = 0) => {
751
+ const spaces = " ".repeat(indent);
752
+ writeErr(`${spaces}${text}`);
753
+ },
591
754
  customRaw: (text, indent = 0) => {
592
755
  const spaces = " ".repeat(indent);
593
756
  writeOut(`${spaces}${customTransform(text)}`);
@@ -735,7 +898,6 @@ function setupGlobalErrorHandlers() {
735
898
  import { execSync as execSync5 } from "child_process";
736
899
  import { writeFileSync as writeFileSync10 } from "fs";
737
900
  import { resolve as resolve9 } from "path";
738
- import { confirm as confirm6 } from "@inquirer/prompts";
739
901
 
740
902
  // ../utils/src/ansi.ts
741
903
  var colors = {
@@ -1013,97 +1175,6 @@ function generateSlug(text) {
1013
1175
  // src/lib/init/run.ts
1014
1176
  init_file_loader();
1015
1177
 
1016
- // ../utils/src/package-manager.ts
1017
- import { execSync } from "child_process";
1018
- import { existsSync as existsSync2 } from "fs";
1019
- import { join } from "path";
1020
- function isCommandAvailable(command) {
1021
- try {
1022
- execSync(`command -v ${command}`, { stdio: "ignore" });
1023
- return true;
1024
- } catch {
1025
- return false;
1026
- }
1027
- }
1028
- function detectPackageManager(cwd = process.cwd()) {
1029
- if (existsSync2(join(cwd, "bun.lock")) || existsSync2(join(cwd, "bun.lockb"))) {
1030
- return "bun";
1031
- }
1032
- if (existsSync2(join(cwd, "pnpm-lock.yaml"))) {
1033
- return "pnpm";
1034
- }
1035
- if (existsSync2(join(cwd, "yarn.lock"))) {
1036
- return "yarn";
1037
- }
1038
- if (existsSync2(join(cwd, "package-lock.json"))) {
1039
- return "npm";
1040
- }
1041
- return detectByCommandAvailability();
1042
- }
1043
- function detectByCommandAvailability() {
1044
- if (isCommandAvailable("bun")) {
1045
- return "bun";
1046
- }
1047
- if (isCommandAvailable("pnpm")) {
1048
- return "pnpm";
1049
- }
1050
- if (isCommandAvailable("yarn")) {
1051
- return "yarn";
1052
- }
1053
- return "npm";
1054
- }
1055
- function getInstallCommand(pm) {
1056
- switch (pm) {
1057
- case "bun": {
1058
- return "bun install";
1059
- }
1060
- case "pnpm": {
1061
- return "pnpm install";
1062
- }
1063
- case "yarn": {
1064
- return "yarn install";
1065
- }
1066
- case "npm":
1067
- default: {
1068
- return "npm install";
1069
- }
1070
- }
1071
- }
1072
- function getRunCommand(pm, script) {
1073
- switch (pm) {
1074
- case "bun": {
1075
- return `bun run ${script}`;
1076
- }
1077
- case "pnpm": {
1078
- return `pnpm run ${script}`;
1079
- }
1080
- case "yarn": {
1081
- return `yarn run ${script}`;
1082
- }
1083
- case "npm":
1084
- default: {
1085
- return `npm run ${script}`;
1086
- }
1087
- }
1088
- }
1089
- function getAddDevDependencyCommand(pm, packageName) {
1090
- switch (pm) {
1091
- case "bun": {
1092
- return `bun add -D ${packageName}`;
1093
- }
1094
- case "pnpm": {
1095
- return `pnpm add -D ${packageName}`;
1096
- }
1097
- case "yarn": {
1098
- return `yarn add -D ${packageName}`;
1099
- }
1100
- case "npm":
1101
- default: {
1102
- return `npm install --save-dev ${packageName}`;
1103
- }
1104
- }
1105
- }
1106
-
1107
1178
  // src/constants/api.ts
1108
1179
  import { join as join3 } from "node:path";
1109
1180
 
@@ -1125,7 +1196,7 @@ var SAMPLE_BUCKET_FILENAME = "bucket.ts";
1125
1196
  // ../better-auth/package.json
1126
1197
  var package_default = {
1127
1198
  name: "@playcademy/better-auth",
1128
- version: "0.0.18",
1199
+ version: "0.0.19-beta.1",
1129
1200
  type: "module",
1130
1201
  exports: {
1131
1202
  "./server": {
@@ -1269,6 +1340,20 @@ var CLI_DEFAULT_OUTPUTS = {
1269
1340
  WORKER_BUNDLE: join6(WORKSPACE_NAME, "worker-bundle.js")
1270
1341
  };
1271
1342
 
1343
+ // src/constants/prompts.ts
1344
+ var NON_INTERACTIVE_HINTS = {
1345
+ API_ROUTES_DIRECTORY: "Run interactively to choose an API routes directory.",
1346
+ DATABASE_DIRECTORY: "Run interactively to choose a database directory.",
1347
+ PROJECT_SLUG: "Run interactively to type the project slug.",
1348
+ CONFIRM_DELETION: "Pass --force or --yes to confirm deletion.",
1349
+ CONFIRM_CLEAR: "Pass --force or --yes to confirm clear.",
1350
+ PROJECT_DIRECTORY: "Pass a project directory argument or run interactively.",
1351
+ MIGRATE_MODE: "Pass --migrate keep or --migrate replace.",
1352
+ BUILD_PATH: "Pass --build or set buildPath in playcademy.config.",
1353
+ DASHBOARD_DRIFT: "Resolve dashboard drift interactively or update local config first.",
1354
+ TIMEBACK_DRIFT: "Resolve TimeBack config drift interactively before deploying."
1355
+ };
1356
+
1272
1357
  // src/constants/timeback.ts
1273
1358
  var CONFIG_FILE_NAMES = [
1274
1359
  "playcademy.config.js",
@@ -1343,33 +1428,6 @@ var DOCS_URL = "https://docs.dev.playcademy.net/platform";
1343
1428
  // src/lib/core/client.ts
1344
1429
  import { PlaycademyClient } from "@playcademy/sdk/internal";
1345
1430
 
1346
- // src/lib/core/context.ts
1347
- import { existsSync as existsSync3 } from "fs";
1348
- import { resolve as resolve2 } from "path";
1349
- var context = {};
1350
- var cache = {
1351
- packageManager: null
1352
- };
1353
- function setCliContext(ctx) {
1354
- context = { ...context, ...ctx };
1355
- }
1356
- function getWorkspace() {
1357
- return context.workspace || process.cwd();
1358
- }
1359
- function getPackageManager() {
1360
- if (cache.packageManager) {
1361
- return cache.packageManager;
1362
- }
1363
- cache.packageManager = detectPackageManager(getWorkspace());
1364
- return cache.packageManager;
1365
- }
1366
- function hasPackageJson(dir) {
1367
- return existsSync3(resolve2(dir || getWorkspace(), "package.json"));
1368
- }
1369
- function isNonInteractive() {
1370
- return process.env.CI === "1" || process.env.CI === "true";
1371
- }
1372
-
1373
1431
  // src/lib/core/errors.ts
1374
1432
  import { ApiError as ApiError2 } from "@playcademy/sdk/internal";
1375
1433
 
@@ -1381,6 +1439,67 @@ function normalizeGitignoreEntry(entry) {
1381
1439
  // src/lib/core/import.ts
1382
1440
  import * as esbuild from "esbuild";
1383
1441
 
1442
+ // src/lib/core/prompts.ts
1443
+ import {
1444
+ checkbox as inquirerCheckbox,
1445
+ confirm as inquirerConfirm,
1446
+ input as inquirerInput,
1447
+ password as inquirerPassword,
1448
+ select as inquirerSelect
1449
+ } from "@inquirer/prompts";
1450
+ var NonInteractivePromptError = class extends Error {
1451
+ constructor(message) {
1452
+ super(message);
1453
+ this.name = "NonInteractivePromptError";
1454
+ }
1455
+ };
1456
+ function describePrompt(message) {
1457
+ return typeof message === "string" && message.trim() ? `Prompt "${message}" cannot run in non-interactive mode.` : "Interactive prompt cannot run in non-interactive mode.";
1458
+ }
1459
+ function buildPromptError(message, hint) {
1460
+ const suffix = hint ? ` ${hint}` : " Provide the required flags or run interactively.";
1461
+ return new NonInteractivePromptError(`${describePrompt(message)}${suffix}`);
1462
+ }
1463
+ function isPromptless() {
1464
+ return shouldAssumeYes() || isNonInteractive();
1465
+ }
1466
+ function resolvePromptless(config) {
1467
+ if (config.nonInteractiveDefault !== void 0) {
1468
+ return config.nonInteractiveDefault;
1469
+ }
1470
+ throw buildPromptError(config.message, config.nonInteractiveHint);
1471
+ }
1472
+ async function confirm(config) {
1473
+ if (isNonInteractive() && config.nonInteractiveDefault !== void 0) {
1474
+ return config.nonInteractiveDefault;
1475
+ }
1476
+ if (shouldAssumeYes()) {
1477
+ return config.assumeYesDefault ?? true;
1478
+ }
1479
+ if (isNonInteractive()) {
1480
+ return resolvePromptless(config);
1481
+ }
1482
+ return await inquirerConfirm(config);
1483
+ }
1484
+ async function input(config) {
1485
+ if (isPromptless()) {
1486
+ return resolvePromptless(config);
1487
+ }
1488
+ return await inquirerInput(config);
1489
+ }
1490
+ async function select(config) {
1491
+ if (isPromptless()) {
1492
+ return resolvePromptless(config);
1493
+ }
1494
+ return await inquirerSelect(config);
1495
+ }
1496
+ async function checkbox(config) {
1497
+ if (isPromptless()) {
1498
+ return resolvePromptless(config);
1499
+ }
1500
+ return await inquirerCheckbox(config);
1501
+ }
1502
+
1384
1503
  // src/lib/core/transpile.ts
1385
1504
  import * as esbuild2 from "esbuild";
1386
1505
 
@@ -2206,7 +2325,6 @@ Source: ${templateSource}`,
2206
2325
  }
2207
2326
 
2208
2327
  // src/lib/init/engine/prompts.ts
2209
- import { select } from "@inquirer/prompts";
2210
2328
  import { cyan as cyan3, magenta as magenta2, yellow as yellow3 } from "colorette";
2211
2329
 
2212
2330
  // src/lib/init/engine/registry.ts
@@ -2393,7 +2511,8 @@ async function promptForEngine() {
2393
2511
  value: "none",
2394
2512
  name: `${yellow3("None")}`
2395
2513
  }
2396
- ]
2514
+ ],
2515
+ nonInteractiveHint: "Run interactively to choose a project type."
2397
2516
  });
2398
2517
  }
2399
2518
  async function promptForFramework(engine) {
@@ -2409,7 +2528,8 @@ async function promptForFramework(engine) {
2409
2528
  choices: config.frameworks.map((fw) => ({
2410
2529
  value: fw,
2411
2530
  name: fw.color(fw.display)
2412
- }))
2531
+ })),
2532
+ nonInteractiveHint: "Run interactively to choose a framework."
2413
2533
  });
2414
2534
  }
2415
2535
  async function promptForTemplate(framework) {
@@ -2421,14 +2541,14 @@ async function promptForTemplate(framework) {
2421
2541
  choices: framework.templates.map((t) => ({
2422
2542
  value: t,
2423
2543
  name: t.color(t.display)
2424
- }))
2544
+ })),
2545
+ nonInteractiveHint: "Run interactively to choose a template variant."
2425
2546
  });
2426
2547
  }
2427
2548
 
2428
2549
  // src/lib/deploy/godot.ts
2429
2550
  import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmSync } from "fs";
2430
2551
  import { join as join10 } from "path";
2431
- import { confirm, select as select2 } from "@inquirer/prompts";
2432
2552
  function isGodotProject() {
2433
2553
  return existsSync7(join10(getWorkspace(), GODOT_PROJECT_FILE));
2434
2554
  }
@@ -2603,20 +2723,21 @@ function ensureRootGitignore(workspace = getWorkspace()) {
2603
2723
  // src/lib/init/project.ts
2604
2724
  import { existsSync as existsSync9, mkdirSync as mkdirSync3 } from "fs";
2605
2725
  import { resolve as resolve6 } from "path";
2606
- import { confirm as confirm2, input, select as select3 } from "@inquirer/prompts";
2607
2726
  async function promptForProjectDirectory(projectDir) {
2608
2727
  let dir = projectDir;
2609
2728
  if (dir === void 0) {
2610
- const choice = await select3({
2729
+ const choice = await select({
2611
2730
  message: "Where do you want to create the project?",
2612
2731
  choices: [
2613
2732
  { value: ".", name: "Current directory" },
2614
2733
  { value: "new", name: "New directory" }
2615
- ]
2734
+ ],
2735
+ nonInteractiveHint: NON_INTERACTIVE_HINTS.PROJECT_DIRECTORY
2616
2736
  });
2617
2737
  if (choice === "new") {
2618
2738
  dir = await input({
2619
- message: "Directory name:"
2739
+ message: "Directory name:",
2740
+ nonInteractiveHint: NON_INTERACTIVE_HINTS.PROJECT_DIRECTORY
2620
2741
  });
2621
2742
  } else {
2622
2743
  dir = ".";
@@ -2632,9 +2753,10 @@ async function promptForProjectDirectory(projectDir) {
2632
2753
  const targetDir = resolve6(process.cwd(), dir);
2633
2754
  if (existsSync9(targetDir)) {
2634
2755
  logger.admonition("warning", "Directory Exists", [`Directory "${dir}" already exists.`]);
2635
- const shouldContinue = await confirm2({
2756
+ const shouldContinue = await confirm({
2636
2757
  message: "Continue and initialize in existing directory?",
2637
- default: false
2758
+ default: false,
2759
+ nonInteractiveHint: "Pass --yes to confirm using the existing directory."
2638
2760
  });
2639
2761
  if (!shouldContinue) {
2640
2762
  logger.newLine();
@@ -2669,7 +2791,6 @@ function createProjectDirectory(info) {
2669
2791
  }
2670
2792
 
2671
2793
  // src/lib/init/prompts.ts
2672
- import { checkbox, confirm as confirm3, input as input2, select as select4 } from "@inquirer/prompts";
2673
2794
  import { bold as bold4, cyan as cyan4 } from "colorette";
2674
2795
 
2675
2796
  // src/lib/init/scaffold.ts
@@ -2830,7 +2951,7 @@ import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as re
2830
2951
  import { join as join13 } from "node:path";
2831
2952
 
2832
2953
  // src/version.ts
2833
- var cliVersion = false ? "0.0.0-dev" : "0.26.0";
2954
+ var cliVersion = false ? "0.0.0-dev" : "0.26.1-beta.2";
2834
2955
 
2835
2956
  // src/lib/init/database.ts
2836
2957
  var drizzleConfigTemplate = loadTemplateString("database/drizzle-config.ts");
@@ -3016,8 +3137,9 @@ function addPlaycademySdk() {
3016
3137
 
3017
3138
  // src/lib/init/prompts.ts
3018
3139
  async function promptForProjectInfo() {
3019
- const name = await input2({
3140
+ const name = await input({
3020
3141
  message: "App name:",
3142
+ nonInteractiveHint: "Run interactively to initialize a project.",
3021
3143
  validate: (value) => {
3022
3144
  if (!value || value.trim().length === 0) {
3023
3145
  return "App name is required";
@@ -3025,11 +3147,11 @@ async function promptForProjectInfo() {
3025
3147
  return true;
3026
3148
  }
3027
3149
  });
3028
- const description = await input2({
3150
+ const description = await input({
3029
3151
  message: "App description (optional):",
3030
3152
  default: ""
3031
3153
  });
3032
- const emoji = await input2({
3154
+ const emoji = await input({
3033
3155
  message: "App emoji (optional):",
3034
3156
  default: "\u{1F3AE}"
3035
3157
  });
@@ -3037,7 +3159,7 @@ async function promptForProjectInfo() {
3037
3159
  }
3038
3160
  async function promptForTimeBackIntegration(options) {
3039
3161
  if (!options?.skipConfirm) {
3040
- const wantsTimeback = await confirm3({
3162
+ const wantsTimeback = await confirm({
3041
3163
  message: "TimeBack?",
3042
3164
  default: false
3043
3165
  });
@@ -3052,6 +3174,7 @@ async function promptForTimeBackIntegration(options) {
3052
3174
  name: subject
3053
3175
  })),
3054
3176
  instructions: ` ${bold4("(Press ")}${cyan4("<space>")}${bold4(" to select and ")}${cyan4("<enter>")}${bold4(" to proceed)")}`,
3177
+ nonInteractiveHint: "Run interactively to configure TimeBack subjects.",
3055
3178
  validate: (selected) => {
3056
3179
  if (!selected || selected.length === 0) {
3057
3180
  return "At least one subject is required";
@@ -3063,12 +3186,13 @@ async function promptForTimeBackIntegration(options) {
3063
3186
  if (subjects.length === 1) {
3064
3187
  primarySubject = subjects[0];
3065
3188
  } else {
3066
- primarySubject = await select4({
3189
+ primarySubject = await select({
3067
3190
  message: "Primary subject (for multi-grade courses):",
3068
3191
  choices: subjects.map((subject) => ({
3069
3192
  value: subject,
3070
3193
  name: subject
3071
- }))
3194
+ })),
3195
+ nonInteractiveHint: "Run interactively to choose a primary TimeBack subject."
3072
3196
  });
3073
3197
  }
3074
3198
  const grades = await checkbox({
@@ -3078,6 +3202,7 @@ async function promptForTimeBackIntegration(options) {
3078
3202
  name: TIMEBACK_GRADE_LEVEL_LABELS[grade.toString()]
3079
3203
  })),
3080
3204
  instructions: ` ${bold4("(Press ")}${cyan4("<space>")}${bold4(" to select and ")}${cyan4("<enter>")}${bold4(" to proceed)")}`,
3205
+ nonInteractiveHint: "Run interactively to configure TimeBack grade levels.",
3081
3206
  validate: (selected) => {
3082
3207
  if (!selected || selected.length === 0) {
3083
3208
  return "At least one grade level is required";
@@ -3097,16 +3222,17 @@ async function promptForTimeBackIntegration(options) {
3097
3222
  return courses;
3098
3223
  }
3099
3224
  async function promptForDatabase() {
3100
- const wantsDatabase = await confirm3({
3225
+ const wantsDatabase = await confirm({
3101
3226
  message: "Database?",
3102
3227
  default: false
3103
3228
  });
3104
3229
  if (!wantsDatabase) {
3105
3230
  return null;
3106
3231
  }
3107
- const directory = await input2({
3232
+ const directory = await input({
3108
3233
  message: "Database directory:",
3109
3234
  default: DEFAULT_DATABASE_DIRECTORY,
3235
+ nonInteractiveHint: NON_INTERACTIVE_HINTS.DATABASE_DIRECTORY,
3110
3236
  validate: (value) => {
3111
3237
  if (!value || value.trim().length === 0) {
3112
3238
  return "Directory name is required";
@@ -3126,6 +3252,7 @@ async function promptForAuthStrategies() {
3126
3252
  { value: "google", name: "Google OAuth" }
3127
3253
  ],
3128
3254
  instructions: ` ${bold4("(Press ")}${cyan4("<space>")}${bold4(" to select and ")}${cyan4("<enter>")}${bold4(" to proceed)")}`,
3255
+ nonInteractiveHint: "Run interactively to choose auth strategies.",
3129
3256
  validate: (selected) => {
3130
3257
  if (!selected.some((s) => s.value === "platform")) {
3131
3258
  return "Platform auth is included by default (cannot be deselected)";
@@ -3136,7 +3263,7 @@ async function promptForAuthStrategies() {
3136
3263
  return strategies.filter((s) => s !== "platform");
3137
3264
  }
3138
3265
  async function promptForAuth() {
3139
- const wantsAuth = await confirm3({
3266
+ const wantsAuth = await confirm({
3140
3267
  message: "Authentication?",
3141
3268
  default: false
3142
3269
  });
@@ -3148,14 +3275,14 @@ async function promptForAuth() {
3148
3275
  return { strategies };
3149
3276
  }
3150
3277
  async function promptForKV() {
3151
- const wantsKV = await confirm3({
3278
+ const wantsKV = await confirm({
3152
3279
  message: "KV storage?",
3153
3280
  default: false
3154
3281
  });
3155
3282
  return wantsKV;
3156
3283
  }
3157
3284
  async function promptForBucket() {
3158
- const wantsBucket = await confirm3({
3285
+ const wantsBucket = await confirm({
3159
3286
  message: "Bucket storage?",
3160
3287
  default: false
3161
3288
  });
@@ -3164,7 +3291,7 @@ async function promptForBucket() {
3164
3291
  async function promptForCustomRoutes(requiresRoutes = false) {
3165
3292
  let wantsCustomRoutes = requiresRoutes;
3166
3293
  if (!requiresRoutes) {
3167
- wantsCustomRoutes = await confirm3({
3294
+ wantsCustomRoutes = await confirm({
3168
3295
  message: "Custom API routes?",
3169
3296
  default: false
3170
3297
  });
@@ -3172,9 +3299,10 @@ async function promptForCustomRoutes(requiresRoutes = false) {
3172
3299
  if (!wantsCustomRoutes) {
3173
3300
  return null;
3174
3301
  }
3175
- const directory = await input2({
3302
+ const directory = await input({
3176
3303
  message: "API routes directory:",
3177
3304
  default: DEFAULT_API_ROUTES_DIRECTORY,
3305
+ nonInteractiveHint: NON_INTERACTIVE_HINTS.API_ROUTES_DIRECTORY,
3178
3306
  validate: (value) => {
3179
3307
  if (!value || value.trim().length === 0) {
3180
3308
  return "Directory name is required";
@@ -3213,13 +3341,14 @@ async function selectConfigFormat(hasPackageJson2) {
3213
3341
  if (hasPackageJson2) {
3214
3342
  return "js";
3215
3343
  }
3216
- const formatChoice = await select4({
3344
+ const formatChoice = await select({
3217
3345
  message: "Which config format would you like to use?",
3218
3346
  choices: [
3219
3347
  { value: "json", name: "JSON (playcademy.config.json)" },
3220
3348
  { value: "js", name: "JavaScript (playcademy.config.js)" }
3221
3349
  ],
3222
- default: "json"
3350
+ default: "json",
3351
+ nonInteractiveHint: "Run interactively to choose a configuration format."
3223
3352
  });
3224
3353
  return formatChoice;
3225
3354
  }
@@ -3230,6 +3359,11 @@ import { existsSync as existsSync15, readFileSync as readFileSync9, writeFileSyn
3230
3359
  import { dirname as dirname5, join as join17, resolve as resolve8 } from "node:path";
3231
3360
  import { fileURLToPath as fileURLToPath2 } from "node:url";
3232
3361
 
3362
+ // ../utils/src/error.ts
3363
+ function errorMessage(err) {
3364
+ return err instanceof Error ? err.message : String(err);
3365
+ }
3366
+
3233
3367
  // src/lib/bundle/backend.ts
3234
3368
  import { existsSync as existsSync13 } from "node:fs";
3235
3369
  import { join as join15 } from "node:path";
@@ -3253,14 +3387,12 @@ function hasHooksModule(workspace) {
3253
3387
  init_file_loader();
3254
3388
 
3255
3389
  // src/lib/timeback/update.ts
3256
- import { confirm as confirm4, select as select5 } from "@inquirer/prompts";
3257
3390
  import { green as green3, red as red3 } from "colorette";
3258
3391
 
3259
3392
  // src/lib/secrets/diff.ts
3260
3393
  import { green as green4, red as red4, yellow as yellow4 } from "colorette";
3261
3394
 
3262
3395
  // src/lib/secrets/sync.ts
3263
- import { confirm as confirm5 } from "@inquirer/prompts";
3264
3396
  import { bold as bold5 } from "colorette";
3265
3397
 
3266
3398
  // src/lib/init/bucket.ts
@@ -3497,7 +3629,7 @@ ${secretTypes}
3497
3629
  }
3498
3630
  }
3499
3631
  async function ensurePlaycademyTypes(options = {}) {
3500
- const { verbose = false } = options;
3632
+ const { quiet = false, verbose = false } = options;
3501
3633
  try {
3502
3634
  const workspace = getWorkspace();
3503
3635
  const config = await loadConfig();
@@ -3533,9 +3665,9 @@ async function ensurePlaycademyTypes(options = {}) {
3533
3665
  logger.success(`Updated <${tsConfigFilename}>`);
3534
3666
  }
3535
3667
  } catch (error) {
3536
- logger.warn(
3537
- `Failed to generate TypeScript types: ${error instanceof Error ? error.message : String(error)}`
3538
- );
3668
+ if (!quiet) {
3669
+ logger.warn(`Failed to generate TypeScript types: ${errorMessage(error)}`);
3670
+ }
3539
3671
  }
3540
3672
  }
3541
3673
 
@@ -3613,14 +3745,10 @@ async function checkExistingConfig(force) {
3613
3745
  logger.admonition("warning", "Already Initialized", [
3614
3746
  `Configuration file already exists: ${relativePath}`
3615
3747
  ]);
3616
- if (isNonInteractive()) {
3617
- logger.remark("Nothing to do");
3618
- logger.newLine();
3619
- return false;
3620
- }
3621
- const shouldOverwrite = await confirm6({
3748
+ const shouldOverwrite = await confirm({
3622
3749
  message: "Do you want to overwrite it?",
3623
- default: false
3750
+ default: false,
3751
+ nonInteractiveDefault: false
3624
3752
  });
3625
3753
  if (!shouldOverwrite) {
3626
3754
  logger.newLine();
@@ -3633,6 +3761,12 @@ async function checkExistingConfig(force) {
3633
3761
  async function runInit(options = {}) {
3634
3762
  logger.raw(motd);
3635
3763
  try {
3764
+ if (isNonInteractive() || shouldAssumeYes()) {
3765
+ logger.admonition("warning", "Interactive Required", [
3766
+ "Run this command in an interactive terminal to finish initialization."
3767
+ ]);
3768
+ return;
3769
+ }
3636
3770
  const dirInfo = await promptForProjectDirectory(options.projectDir);
3637
3771
  if (dirInfo.cancelled) {
3638
3772
  return;
@@ -3642,12 +3776,6 @@ async function runInit(options = {}) {
3642
3776
  if (!canProceed) {
3643
3777
  return;
3644
3778
  }
3645
- if (isNonInteractive()) {
3646
- logger.admonition("warning", "Interactive Required", [
3647
- "Run this command in an interactive terminal to finish initialization."
3648
- ]);
3649
- return;
3650
- }
3651
3779
  let configFormat;
3652
3780
  if (engineSelection?.engine === "godot") {
3653
3781
  configFormat = "json";