create-avalon 0.1.24 → 0.1.25

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 (3) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.js +316 -46
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -22,6 +22,7 @@ The CLI walks you through:
22
22
  - Framework selection (React, Preact, Vue, Svelte, Solid, Lit, Qwik — or multiple)
23
23
  - Styling approach (CSS Modules, Tailwind, vanilla CSS)
24
24
  - Optional features (API routes, middleware, layouts, MDX)
25
+ - Scheduled jobs (cron) — scaffolds an example task and wires up `nitro.cron`
25
26
  - Package manager preference
26
27
 
27
28
  ## What you get
@@ -43,6 +44,7 @@ my-project/
43
44
  ├── middleware/ # Server middleware
44
45
  ├── routes/
45
46
  │ └── api/ # API routes
47
+ ├── tasks/ # Scheduled jobs (cron) — optional
46
48
  ├── server/ # Server config & env
47
49
  ├── public/ # Static assets
48
50
  ├── vite.config.ts
package/dist/cli.js CHANGED
@@ -76,12 +76,65 @@ var require_src = __commonJS((exports, module) => {
76
76
  });
77
77
 
78
78
  // src/cli.ts
79
- import { basename, resolve } from "node:path";
80
79
  import { createRequire } from "node:module";
80
+ import { basename, resolve } from "node:path";
81
81
 
82
82
  // src/cli-utils.ts
83
- import { parseArgs } from "node:util";
84
83
  import { existsSync, readdirSync } from "node:fs";
84
+ import { parseArgs } from "node:util";
85
+
86
+ // src/types.ts
87
+ var RENDER_ENGINES = ["preact", "react"];
88
+ var INTEGRATIONS = [
89
+ "preact",
90
+ "react",
91
+ "vue",
92
+ "svelte",
93
+ "solid",
94
+ "lit",
95
+ "qwik"
96
+ ];
97
+ var STYLING_OPTIONS = [
98
+ "css-modules",
99
+ "tailwind",
100
+ "shadcn"
101
+ ];
102
+ var PLUGINS = [
103
+ "seo",
104
+ "agent-optimization",
105
+ "syntax-highlighting"
106
+ ];
107
+ var MIDDLEWARE_OPTIONS = [
108
+ "h3",
109
+ "hono",
110
+ "elysia"
111
+ ];
112
+ var DEPLOY_TARGETS = ["netlify", "none"];
113
+ var INTEGRATION_PACKAGES = {
114
+ preact: "@useavalon/preact",
115
+ react: "@useavalon/react",
116
+ vue: "@useavalon/vue",
117
+ svelte: "@useavalon/svelte",
118
+ solid: "@useavalon/solid",
119
+ lit: "@useavalon/lit",
120
+ qwik: "@useavalon/qwik"
121
+ };
122
+ var BASE_DIRS = [
123
+ "app/modules/main/pages",
124
+ "app/modules/main/components",
125
+ "app/modules/main/layouts",
126
+ "app/shared/layouts",
127
+ "app/shared/components",
128
+ "app/shared/styles",
129
+ "middleware",
130
+ "routes/api",
131
+ "public",
132
+ "server"
133
+ ];
134
+
135
+ // src/cli-utils.ts
136
+ class CliArgError extends Error {
137
+ }
85
138
  function validateDirectory(dir) {
86
139
  if (!existsSync(dir)) {
87
140
  return { valid: true };
@@ -100,7 +153,15 @@ function parseCliArgs(argv) {
100
153
  args: argv,
101
154
  options: {
102
155
  help: { type: "boolean", default: false, short: "h" },
103
- version: { type: "boolean", default: false, short: "v" }
156
+ version: { type: "boolean", default: false, short: "v" },
157
+ yes: { type: "boolean", default: false, short: "y" },
158
+ core: { type: "string" },
159
+ integrations: { type: "string" },
160
+ styling: { type: "string" },
161
+ plugins: { type: "string" },
162
+ middleware: { type: "string" },
163
+ deploy: { type: "string" },
164
+ cron: { type: "boolean", default: false }
104
165
  },
105
166
  strict: true,
106
167
  allowPositionals: true
@@ -108,7 +169,58 @@ function parseCliArgs(argv) {
108
169
  return {
109
170
  projectName: positionals[0] ?? undefined,
110
171
  help: values.help ?? false,
111
- version: values.version ?? false
172
+ version: values.version ?? false,
173
+ yes: values.yes ?? false,
174
+ core: values.core,
175
+ integrations: values.integrations,
176
+ styling: values.styling,
177
+ plugins: values.plugins,
178
+ middleware: values.middleware,
179
+ deploy: values.deploy,
180
+ cron: values.cron ?? false
181
+ };
182
+ }
183
+ var csv = (value) => value ? value.split(",").map((v) => v.trim()).filter(Boolean) : undefined;
184
+ function assertOneOf(value, allowed, flag) {
185
+ if (value === undefined)
186
+ return;
187
+ if (!allowed.includes(value)) {
188
+ throw new CliArgError(`Invalid value "${value}" for --${flag}. Allowed: ${allowed.join(", ")}.`);
189
+ }
190
+ return value;
191
+ }
192
+ function assertAllOf(values, allowed, flag) {
193
+ if (values === undefined)
194
+ return;
195
+ for (const value of values) {
196
+ if (!allowed.includes(value)) {
197
+ throw new CliArgError(`Invalid value "${value}" for --${flag}. Allowed: ${allowed.join(", ")}.`);
198
+ }
199
+ }
200
+ return values;
201
+ }
202
+ function resolveConfigNonInteractive(args) {
203
+ const core = assertOneOf(args.core, RENDER_ENGINES, "core") ?? "preact";
204
+ const integrations = assertAllOf(csv(args.integrations), INTEGRATIONS, "integrations") ?? [];
205
+ const styling = assertOneOf(args.styling, STYLING_OPTIONS, "styling") ?? "css-modules";
206
+ const plugins = assertAllOf(csv(args.plugins), PLUGINS, "plugins") ?? ["seo"];
207
+ const middleware = assertOneOf(args.middleware, MIDDLEWARE_OPTIONS, "middleware") ?? "h3";
208
+ const deploy = assertOneOf(args.deploy, DEPLOY_TARGETS, "deploy") ?? "none";
209
+ if (styling === "shadcn" && core !== "react") {
210
+ throw new CliArgError("--styling=shadcn requires --core=react (shadcn is Radix/React based).");
211
+ }
212
+ if (core === "react" && !integrations.includes("react")) {
213
+ integrations.push("react");
214
+ }
215
+ return {
216
+ projectName: args.projectName ?? ".",
217
+ core,
218
+ integrations,
219
+ styling,
220
+ plugins,
221
+ middleware,
222
+ deploy,
223
+ cron: args.cron
112
224
  };
113
225
  }
114
226
 
@@ -543,6 +655,25 @@ class Vt extends B {
543
655
  }
544
656
  }
545
657
  }
658
+
659
+ class kt extends B {
660
+ get cursor() {
661
+ return this.value ? 0 : 1;
662
+ }
663
+ get _value() {
664
+ return this.cursor === 0;
665
+ }
666
+ constructor(e) {
667
+ super(e, false), this.value = !!e.initialValue, this.on("userInput", () => {
668
+ this.value = this._value;
669
+ }), this.on("confirm", (s) => {
670
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = s, this.state = "submit", this.close();
671
+ }), this.on("cursor", () => {
672
+ this.value = !this.value;
673
+ });
674
+ }
675
+ }
676
+
546
677
  class yt extends B {
547
678
  options;
548
679
  cursor = 0;
@@ -961,6 +1092,33 @@ var X2 = ({ cursor: e, options: r, style: s, output: i = process.stdout, maxItem
961
1092
  C.push(b);
962
1093
  return $ && C.push(c), C;
963
1094
  };
1095
+ var Rt = (e) => {
1096
+ const r = e.active ?? "Yes", s = e.inactive ?? "No";
1097
+ return new kt({ active: r, inactive: s, signal: e.signal, input: e.input, output: e.output, initialValue: e.initialValue ?? true, render() {
1098
+ const i = e.withGuide ?? _.withGuide, a = `${i ? `${t("gray", h)}
1099
+ ` : ""}${W2(this.state)} ${e.message}
1100
+ `, o = this.value ? r : s;
1101
+ switch (this.state) {
1102
+ case "submit": {
1103
+ const u = i ? `${t("gray", h)} ` : "";
1104
+ return `${a}${u}${t("dim", o)}`;
1105
+ }
1106
+ case "cancel": {
1107
+ const u = i ? `${t("gray", h)} ` : "";
1108
+ return `${a}${u}${t(["strikethrough", "dim"], o)}${i ? `
1109
+ ${t("gray", h)}` : ""}`;
1110
+ }
1111
+ default: {
1112
+ const u = i ? `${t("cyan", h)} ` : "", l = i ? t("cyan", x2) : "";
1113
+ return `${a}${u}${this.value ? `${t("green", z2)} ${r}` : `${t("dim", H2)} ${t("dim", r)}`}${e.vertical ? i ? `
1114
+ ${t("cyan", h)} ` : `
1115
+ ` : ` ${t("dim", "/")} `}${this.value ? `${t("dim", H2)} ${t("dim", s)}` : `${t("green", z2)} ${s}`}
1116
+ ${l}
1117
+ `;
1118
+ }
1119
+ }
1120
+ } }).prompt();
1121
+ };
964
1122
  var Nt = (e = "", r) => {
965
1123
  const s = r?.output ?? process.stdout, i = r?.withGuide ?? _.withGuide ? `${t("gray", x2)} ` : "";
966
1124
  s.write(`${i}${t("red", e)}
@@ -1124,6 +1282,26 @@ async function collectProjectConfig(initialName) {
1124
1282
  }
1125
1283
  projectName = nameResult;
1126
1284
  }
1285
+ const coreResult = await Jt({
1286
+ message: "Which rendering engine should render your pages (the shell)?",
1287
+ options: [
1288
+ {
1289
+ value: "preact",
1290
+ label: "Preact",
1291
+ hint: "Smallest runtime (default). React libs run via preact/compat."
1292
+ },
1293
+ {
1294
+ value: "react",
1295
+ label: "React",
1296
+ hint: "Real react-dom/server. React libs like Radix/shadcn work natively."
1297
+ }
1298
+ ],
1299
+ initialValue: "preact"
1300
+ });
1301
+ if (Ct(coreResult)) {
1302
+ Nt("Operation cancelled.");
1303
+ process.exit(1);
1304
+ }
1127
1305
  const integrationsResult = await Lt2({
1128
1306
  message: "Which integrations would you like to include? (use space to toggle, enter to confirm)",
1129
1307
  options: [
@@ -1141,13 +1319,20 @@ async function collectProjectConfig(initialName) {
1141
1319
  Nt("Operation cancelled.");
1142
1320
  process.exit(1);
1143
1321
  }
1322
+ const stylingOptions = [
1323
+ { value: "css-modules", label: "CSS Modules" },
1324
+ { value: "tailwind", label: "Tailwind CSS" }
1325
+ ];
1326
+ if (coreResult === "react") {
1327
+ stylingOptions.push({
1328
+ value: "shadcn",
1329
+ label: "shadcn",
1330
+ hint: "Radix-based components — requires the React engine"
1331
+ });
1332
+ }
1144
1333
  const stylingResult = await Jt({
1145
1334
  message: "Which styling approach would you like to use?",
1146
- options: [
1147
- { value: "css-modules", label: "CSS Modules" },
1148
- { value: "tailwind", label: "Tailwind CSS" },
1149
- { value: "shadcn", label: "shadcn" }
1150
- ]
1335
+ options: stylingOptions
1151
1336
  });
1152
1337
  if (Ct(stylingResult)) {
1153
1338
  Nt("Operation cancelled.");
@@ -1156,8 +1341,16 @@ async function collectProjectConfig(initialName) {
1156
1341
  const pluginsResult = await Lt2({
1157
1342
  message: "Which plugins would you like to include? (use space to toggle, enter to confirm)",
1158
1343
  options: [
1159
- { value: "seo", label: "seo", hint: "Auto-injects OG, Twitter cards, JSON-LD, canonical URLs" },
1160
- { value: "agent-optimization", label: "agent-optimization", hint: "LLM/AI optimization (llms.txt, markdown, sitemap)" },
1344
+ {
1345
+ value: "seo",
1346
+ label: "seo",
1347
+ hint: "Auto-injects OG, Twitter cards, JSON-LD, canonical URLs"
1348
+ },
1349
+ {
1350
+ value: "agent-optimization",
1351
+ label: "agent-optimization",
1352
+ hint: "LLM/AI optimization (llms.txt, markdown, sitemap)"
1353
+ },
1161
1354
  {
1162
1355
  value: "syntax-highlighting",
1163
1356
  label: "syntax-highlighting",
@@ -1186,7 +1379,11 @@ async function collectProjectConfig(initialName) {
1186
1379
  const deployResult = await Jt({
1187
1380
  message: "Where will you deploy?",
1188
1381
  options: [
1189
- { value: "netlify", label: "Netlify", hint: "Generates netlify.toml, build.mjs, post-build.mjs" },
1382
+ {
1383
+ value: "netlify",
1384
+ label: "Netlify",
1385
+ hint: "Generates netlify.toml, build.mjs, post-build.mjs"
1386
+ },
1190
1387
  { value: "none", label: "None / Other", hint: "Node server preset, no deploy config" }
1191
1388
  ]
1192
1389
  });
@@ -1194,13 +1391,28 @@ async function collectProjectConfig(initialName) {
1194
1391
  Nt("Operation cancelled.");
1195
1392
  process.exit(1);
1196
1393
  }
1394
+ const cronResult = await Rt({
1395
+ message: "Set up scheduled jobs (cron)?",
1396
+ initialValue: false
1397
+ });
1398
+ if (Ct(cronResult)) {
1399
+ Nt("Operation cancelled.");
1400
+ process.exit(1);
1401
+ }
1402
+ const core = coreResult;
1403
+ const integrations = integrationsResult;
1404
+ if (core === "react" && !integrations.includes("react")) {
1405
+ integrations.push("react");
1406
+ }
1197
1407
  return {
1198
1408
  projectName,
1199
- integrations: integrationsResult,
1409
+ core,
1410
+ integrations,
1200
1411
  styling: stylingResult,
1201
1412
  plugins: pluginsResult,
1202
1413
  middleware: middlewareResult,
1203
- deploy: deployResult
1414
+ deploy: deployResult,
1415
+ cron: cronResult
1204
1416
  };
1205
1417
  }
1206
1418
 
@@ -1218,6 +1430,31 @@ export default defineHandler(() => {
1218
1430
  `;
1219
1431
  }
1220
1432
 
1433
+ // src/templates/cron.ts
1434
+ var EXAMPLE_CRON_HANDLER = "tasks/cleanup.ts";
1435
+ var EXAMPLE_CRON_SCHEDULE = "0 * * * *";
1436
+ function generateExampleCronTask(_config) {
1437
+ return `import { defineCronJob } from '@useavalon/avalon/cron';
1438
+
1439
+ /**
1440
+ * Example scheduled job. Runs on the schedule defined in vite.config.ts
1441
+ * (\`nitro.cron\`). The task name is derived from this file path: "cleanup".
1442
+ *
1443
+ * In production this runs via your deployment preset's scheduler
1444
+ * (Vercel Cron, Cloudflare Triggers, or the Node server's in-process
1445
+ * scheduler). In development Avalon runs it inside the Vite dev server.
1446
+ */
1447
+ export default defineCronJob({
1448
+ meta: { description: 'Example scheduled job' },
1449
+ async run() {
1450
+ console.log('[cron] cleanup ran at', new Date().toISOString());
1451
+ // TODO: replace with your scheduled work.
1452
+ return { result: 'ok' };
1453
+ },
1454
+ });
1455
+ `;
1456
+ }
1457
+
1221
1458
  // src/templates/deploy.ts
1222
1459
  function generateNetlifyToml(_config) {
1223
1460
  return `[build]
@@ -1453,36 +1690,28 @@ export default defineHandler((event) => {
1453
1690
  `;
1454
1691
  }
1455
1692
 
1456
- // src/types.ts
1457
- var INTEGRATION_PACKAGES = {
1458
- preact: "@useavalon/preact",
1459
- react: "@useavalon/react",
1460
- vue: "@useavalon/vue",
1461
- svelte: "@useavalon/svelte",
1462
- solid: "@useavalon/solid",
1463
- lit: "@useavalon/lit",
1464
- qwik: "@useavalon/qwik"
1465
- };
1466
- var BASE_DIRS = [
1467
- "app/modules/main/pages",
1468
- "app/modules/main/components",
1469
- "app/modules/main/layouts",
1470
- "app/shared/layouts",
1471
- "app/shared/components",
1472
- "app/shared/styles",
1473
- "middleware",
1474
- "routes/api",
1475
- "public",
1476
- "server"
1477
- ];
1478
-
1479
1693
  // src/templates/package-json.ts
1694
+ var INTEGRATION_RUNTIME_DEPS = {
1695
+ preact: { preact: "^10.0.0", "preact-render-to-string": "^6.0.0" },
1696
+ react: { react: "^19.0.0", "react-dom": "^19.0.0" },
1697
+ vue: { vue: "^3.4.0" },
1698
+ svelte: { svelte: "^5.0.0" },
1699
+ solid: { "solid-js": "^1.8.0" },
1700
+ lit: {
1701
+ lit: "^3.0.0",
1702
+ "@lit-labs/ssr": "^4.0.0",
1703
+ "@lit-labs/ssr-client": "^1.0.0",
1704
+ "@lit-labs/ssr-dom-shim": "^1.0.0"
1705
+ },
1706
+ qwik: { "@builder.io/qwik": "^1.5.0" }
1707
+ };
1480
1708
  function generatePackageJson(config) {
1481
1709
  const dependencies = {
1482
1710
  "@useavalon/avalon": "latest"
1483
1711
  };
1484
1712
  for (const integration of config.integrations) {
1485
1713
  dependencies[INTEGRATION_PACKAGES[integration]] = "latest";
1714
+ Object.assign(dependencies, INTEGRATION_RUNTIME_DEPS[integration]);
1486
1715
  }
1487
1716
  if (config.plugins.includes("seo")) {
1488
1717
  dependencies["@useavalon/seo"] = "latest";
@@ -1830,7 +2059,7 @@ function generateShadcnComponentsJson(config) {
1830
2059
  }
1831
2060
 
1832
2061
  // src/templates/tsconfig.ts
1833
- function generateTsConfig() {
2062
+ function generateTsConfig(core = "preact") {
1834
2063
  const tsconfig = {
1835
2064
  compilerOptions: {
1836
2065
  target: "ESNext",
@@ -1843,6 +2072,7 @@ function generateTsConfig() {
1843
2072
  allowImportingTsExtensions: true,
1844
2073
  noEmit: true,
1845
2074
  jsx: "react-jsx",
2075
+ jsxImportSource: core,
1846
2076
  paths: {
1847
2077
  "@shared/*": ["./app/shared/*"],
1848
2078
  "@modules/*": ["./app/modules/*"]
@@ -1943,12 +2173,20 @@ function generateViteConfig(config) {
1943
2173
  if (needsTailwind) {
1944
2174
  pluginEntries.push(` tailwindcss(),`);
1945
2175
  }
2176
+ const cronLines = config.cron ? [
2177
+ ` // Scheduled jobs (cron). Each entry maps a schedule to a task file`,
2178
+ ` // in tasks/. See https://useavalon.dev/docs/cron-jobs`,
2179
+ ` cron: [`,
2180
+ ` { schedule: '${EXAMPLE_CRON_SCHEDULE}', handler: '${EXAMPLE_CRON_HANDLER}' },`,
2181
+ ` ],`
2182
+ ] : [];
1946
2183
  const lines = [
1947
2184
  imports.join(`
1948
2185
  `),
1949
2186
  "",
1950
2187
  `export default defineConfig(async (): Promise<UserConfig> => {`,
1951
2188
  ` const avalonPlugins = await avalon({`,
2189
+ ` core: '${config.core}',`,
1952
2190
  ` integrations: [${integrationsList}],`,
1953
2191
  ` modules: 'app/modules',`,
1954
2192
  ` layoutsDir: 'app/shared/layouts',`,
@@ -1963,6 +2201,7 @@ function generateViteConfig(config) {
1963
2201
  ` crawlLinks: true,`,
1964
2202
  ` ignore: [],`,
1965
2203
  ` },`,
2204
+ ...cronLines,
1966
2205
  ` },`,
1967
2206
  ` });`,
1968
2207
  "",
@@ -2053,7 +2292,7 @@ async function scaffoldProject(config, targetDir) {
2053
2292
  await mkdir(join(targetDir, dir), { recursive: true });
2054
2293
  }
2055
2294
  await writeFile(join(targetDir, "package.json"), generatePackageJson(config));
2056
- await writeFile(join(targetDir, "tsconfig.json"), generateTsConfig());
2295
+ await writeFile(join(targetDir, "tsconfig.json"), generateTsConfig(config.core));
2057
2296
  await writeFile(join(targetDir, "vite.config.ts"), generateViteConfig(config));
2058
2297
  await writeFile(join(targetDir, "app/shared/layouts/_layout.tsx"), generateRootLayout(config));
2059
2298
  await writeFile(join(targetDir, "app/modules/main/layouts/_layout.tsx"), generateMainLayout(config));
@@ -2061,6 +2300,11 @@ async function scaffoldProject(config, targetDir) {
2061
2300
  await writeFile(join(targetDir, "app/modules/main/pages/404.tsx"), generate404Page());
2062
2301
  await writeFile(join(targetDir, "middleware/01.logger.ts"), generateSampleMiddleware(config));
2063
2302
  await writeFile(join(targetDir, "routes/api/hello.ts"), generateHelloRoute(config));
2303
+ if (config.cron) {
2304
+ const cronPath = join(targetDir, EXAMPLE_CRON_HANDLER);
2305
+ await mkdir(dirname(cronPath), { recursive: true });
2306
+ await writeFile(cronPath, generateExampleCronTask(config));
2307
+ }
2064
2308
  if (config.middleware === "hono") {
2065
2309
  await writeFile(join(targetDir, "server.ts"), generateHonoServerEntry());
2066
2310
  } else if (config.middleware === "elysia") {
@@ -2076,6 +2320,8 @@ async function scaffoldProject(config, targetDir) {
2076
2320
  await writeFile(join(targetDir, "server/env.d.ts"), `/// <reference types="nitro" />
2077
2321
  `);
2078
2322
  await writeFile(join(targetDir, "app/env.d.ts"), generateEnvDts(config.integrations));
2323
+ await writeFile(join(targetDir, "app/entry-client.ts"), `import "virtual:avalon/client-entry";
2324
+ `);
2079
2325
  await writeFile(join(targetDir, "server/renderer.ts"), [
2080
2326
  `/**`,
2081
2327
  ` * SSR Renderer — provided by Avalon's virtual module system.`,
@@ -2121,6 +2367,7 @@ function formatSummary(config, scaffoldedInPlace = false) {
2121
2367
  ` Plugins: ${plugins}`,
2122
2368
  ` Middleware: ${config.middleware}`,
2123
2369
  ` Deploy: ${deploy}`,
2370
+ ` Cron: ${config.cron ? "yes" : "no"}`,
2124
2371
  "",
2125
2372
  " Next steps:",
2126
2373
  ...nextSteps,
@@ -2142,11 +2389,28 @@ async function main() {
2142
2389
  process.exit(0);
2143
2390
  }
2144
2391
  if (args.help) {
2145
- console.log(`Usage: create-avalon [project-name]
2146
-
2147
- Options:
2148
- -v, --version Show version number
2149
- -h, --help Show help`);
2392
+ console.log([
2393
+ "Usage: create-avalon [project-name] [options]",
2394
+ "",
2395
+ "Runs interactively by default. Pass --yes (or run without a TTY, e.g. in",
2396
+ "CI/Docker) to scaffold non-interactively from flags + defaults.",
2397
+ "",
2398
+ "Options:",
2399
+ " -v, --version Show version number",
2400
+ " -h, --help Show help",
2401
+ " -y, --yes Skip prompts; use flags and defaults",
2402
+ " --core Rendering engine: preact (default) | react",
2403
+ " --integrations Comma list: preact,react,vue,svelte,solid,lit,qwik",
2404
+ " --styling css-modules (default) | tailwind | shadcn",
2405
+ " --plugins Comma list: seo (default),agent-optimization,syntax-highlighting",
2406
+ " --middleware h3 (default) | hono | elysia",
2407
+ " --deploy netlify | none (default)",
2408
+ " --cron Scaffold an example cron task + config",
2409
+ "",
2410
+ "Example:",
2411
+ " create-avalon my-app --yes --core react --integrations react,vue --styling shadcn"
2412
+ ].join(`
2413
+ `));
2150
2414
  process.exit(0);
2151
2415
  }
2152
2416
  if (args.projectName && args.projectName !== ".") {
@@ -2156,7 +2420,8 @@ Options:
2156
2420
  process.exit(1);
2157
2421
  }
2158
2422
  }
2159
- const config = await collectProjectConfig(args.projectName);
2423
+ const nonInteractive = args.yes || !process.stdin.isTTY;
2424
+ const config = nonInteractive ? resolveConfigNonInteractive(args) : await collectProjectConfig(args.projectName);
2160
2425
  if (!args.projectName && config.projectName !== ".") {
2161
2426
  const dirResult = validateDirectory(resolve(config.projectName));
2162
2427
  if (!dirResult.valid) {
@@ -2173,4 +2438,9 @@ Options:
2173
2438
  printSummary(config, scaffoldedInPlace);
2174
2439
  process.exit(0);
2175
2440
  }
2176
- main();
2441
+ try {
2442
+ await main();
2443
+ } catch (error) {
2444
+ console.error(error instanceof CliArgError ? error.message : error);
2445
+ process.exit(1);
2446
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-avalon",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "Scaffold a new Avalon project with multi-framework islands architecture",
5
5
  "license": "MIT",
6
6
  "type": "module",