vela 0.11.1 → 0.11.3

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/bin.js CHANGED
@@ -21,7 +21,7 @@ import pc38 from "picocolors";
21
21
  // package.json
22
22
  var package_default = {
23
23
  name: "vela",
24
- version: "0.11.1",
24
+ version: "0.11.3",
25
25
  type: "module",
26
26
  description: "A CLI for creating and updating SvelteKit projects",
27
27
  license: "MIT",
@@ -55,7 +55,7 @@ var package_default = {
55
55
  dependencies: {
56
56
  "@clack/prompts": "^1.7.0",
57
57
  "@faker-js/faker": "^10.6.0",
58
- "@velastack/patterns": "^0.2.2",
58
+ "@velastack/patterns": "^0.2.3",
59
59
  "@velastack/pocketbase-codegen": "^0.1.0",
60
60
  "annotate-json-schema": "^0.1.0",
61
61
  commander: "^13.1.0",
@@ -71,6 +71,7 @@ var package_default = {
71
71
  "pocketbase-server": "^0.39.11",
72
72
  stripe: "^19.3.0",
73
73
  svelte: "^5.56.10",
74
+ tar: "^7.5.22",
74
75
  tinyexec: "^1.3.0",
75
76
  "ts-morph": "^28.0.0",
76
77
  valibot: "^1.4.2"
@@ -236,6 +237,7 @@ var API_URL = (process2.env.VELA_API_URL?.trim() || "https://velastack.dev").rep
236
237
  ""
237
238
  );
238
239
  var FIXTURE_PREFIX = "vela";
240
+ var TEMPLATE_INDEX_URL = process2.env.VELA_TEMPLATE_INDEX_URL?.trim() || "https://templates.velastack.app/index.json";
239
241
 
240
242
  // src/lib/package-json.ts
241
243
  import fs from "node:fs";
@@ -286,8 +288,8 @@ function mergePackageJson(user, template) {
286
288
  }
287
289
  return { merged, added, conflicts, replaced };
288
290
  }
289
- function readPackageJson(path45) {
290
- return JSON.parse(fs.readFileSync(path45, "utf8"));
291
+ function readPackageJson(path46) {
292
+ return JSON.parse(fs.readFileSync(path46, "utf8"));
291
293
  }
292
294
  var PACKAGE_NAME_PLACEHOLDER = /~TODO~/g;
293
295
  var APP_NAME_PLACEHOLDER = /~APP_NAME~/g;
@@ -300,12 +302,12 @@ function fillTemplatePlaceholders(raw, values) {
300
302
  function escapeSingleQuoted(value) {
301
303
  return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
302
304
  }
303
- function readTemplatePackageJson(path45, values) {
304
- const raw = fillTemplatePlaceholders(fs.readFileSync(path45, "utf8"), values);
305
+ function readTemplatePackageJson(path46, values) {
306
+ const raw = fillTemplatePlaceholders(fs.readFileSync(path46, "utf8"), values);
305
307
  return JSON.parse(raw);
306
308
  }
307
- function writePackageJson(path45, pkg) {
308
- fs.writeFileSync(path45, JSON.stringify(pkg, null, " ") + "\n");
309
+ function writePackageJson(path46, pkg) {
310
+ fs.writeFileSync(path46, JSON.stringify(pkg, null, " ") + "\n");
309
311
  }
310
312
  function toValidPackageName(name) {
311
313
  return name.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._]/, "").replace(/[^a-z0-9~.-]+/g, "-");
@@ -383,10 +385,10 @@ function detectFeatures(root, { isAppMode, isPaymentsMode }) {
383
385
  }
384
386
 
385
387
  // src/commands/bless.ts
386
- import fs13 from "node:fs";
387
- import path11 from "node:path";
388
- import process6 from "node:process";
389
- import * as v2 from "valibot";
388
+ import fs15 from "node:fs";
389
+ import path13 from "node:path";
390
+ import process7 from "node:process";
391
+ import * as v3 from "valibot";
390
392
  import { Command as Command2 } from "commander";
391
393
  import * as p4 from "@clack/prompts";
392
394
  import pc3 from "picocolors";
@@ -420,32 +422,279 @@ function toFlag(key) {
420
422
  }
421
423
 
422
424
  // src/lib/templates.ts
425
+ import fs6 from "node:fs";
426
+ import path5 from "node:path";
427
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
428
+
429
+ // src/lib/template-files.ts
423
430
  import fs3 from "node:fs";
424
431
  import path2 from "node:path";
432
+ var PUBLISH_SAFE_NAMES = {
433
+ ".gitignore": "_gitignore",
434
+ ".npmrc": "_npmrc"
435
+ };
436
+ function templateName(projectRelPath) {
437
+ const safe = PUBLISH_SAFE_NAMES[path2.basename(projectRelPath)];
438
+ if (!safe) return projectRelPath;
439
+ const dir = path2.dirname(projectRelPath);
440
+ return dir === "." ? safe : path2.join(dir, safe);
441
+ }
442
+ function restoreTemplateNames(target) {
443
+ for (const [real, safe] of Object.entries(PUBLISH_SAFE_NAMES)) {
444
+ const from = path2.join(target, safe);
445
+ if (!fs3.existsSync(from)) continue;
446
+ fs3.renameSync(from, path2.join(target, real));
447
+ }
448
+ }
449
+ var TEMPLATE_SOURCE = /\.template\.([^.]+)$/;
450
+ function applyTemplateFiles(target, values) {
451
+ const written = [];
452
+ for (const source of findTemplateSources(target)) {
453
+ const raw = fs3.readFileSync(source, "utf8");
454
+ const dest = source.replace(TEMPLATE_SOURCE, ".$1");
455
+ fs3.writeFileSync(dest, fillTemplatePlaceholders(raw, values));
456
+ fs3.unlinkSync(source);
457
+ written.push(path2.relative(target, dest));
458
+ }
459
+ return written.sort();
460
+ }
461
+ function findTemplateSources(dir) {
462
+ const found = [];
463
+ for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
464
+ const full = path2.join(dir, entry.name);
465
+ if (entry.isDirectory()) {
466
+ if (entry.name === "node_modules" || entry.name === ".git") continue;
467
+ found.push(...findTemplateSources(full));
468
+ } else if (entry.isFile() && TEMPLATE_SOURCE.test(entry.name)) {
469
+ found.push(full);
470
+ }
471
+ }
472
+ return found;
473
+ }
474
+
475
+ // src/lib/template-registry.ts
476
+ import fs5 from "node:fs";
477
+ import os2 from "node:os";
478
+ import path4 from "node:path";
479
+ import { createHash } from "node:crypto";
425
480
  import { fileURLToPath } from "node:url";
481
+ import * as v2 from "valibot";
482
+ import * as tar from "tar";
483
+
484
+ // src/lib/config.ts
485
+ import fs4 from "node:fs";
486
+ import os from "node:os";
487
+ import path3 from "node:path";
488
+ import process4 from "node:process";
489
+ function configDir() {
490
+ return path3.join(os.homedir(), ".vela");
491
+ }
492
+ var CONFIG_DIR = configDir();
493
+ var CONFIG_PATH = path3.join(CONFIG_DIR, "config.json");
494
+ function readConfig() {
495
+ if (!fs4.existsSync(CONFIG_PATH)) return null;
496
+ try {
497
+ return JSON.parse(fs4.readFileSync(CONFIG_PATH, "utf8"));
498
+ } catch {
499
+ return null;
500
+ }
501
+ }
502
+ function writeConfig(config) {
503
+ fs4.mkdirSync(CONFIG_DIR, { recursive: true });
504
+ fs4.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
505
+ }
506
+ function clearConfig() {
507
+ if (fs4.existsSync(CONFIG_PATH)) fs4.unlinkSync(CONFIG_PATH);
508
+ }
509
+ function readApiKey() {
510
+ const fromEnv = process4.env.VELA_API_KEY?.trim();
511
+ if (fromEnv) return fromEnv;
512
+ return readConfig()?.apiKey ?? null;
513
+ }
514
+ function requireApiKey() {
515
+ const apiKey = readApiKey();
516
+ if (!apiKey) {
517
+ throw new Error("Not logged in. Run `vela login` to login, or set VELA_API_KEY.");
518
+ }
519
+ return apiKey;
520
+ }
521
+
522
+ // src/lib/template-registry.ts
523
+ var CACHE_DIR_NAME = "templates";
524
+ var INDEX_CACHE_FILE = "index.json";
525
+ var TARBALL_CACHE_DIR = "cache";
526
+ var INDEX_CACHE_TTL_MS = 60 * 60 * 1e3;
527
+ var DEFAULT_TIMEOUT_MS = 5e3;
528
+ var entrySchema = v2.object({
529
+ name: v2.pipe(v2.string(), v2.regex(/^[a-z0-9][a-z0-9-]*$/)),
530
+ description: v2.string(),
531
+ backend: v2.boolean(),
532
+ title: v2.optional(v2.string()),
533
+ category: v2.optional(v2.string()),
534
+ tags: v2.optional(v2.array(v2.string())),
535
+ price: v2.optional(v2.number()),
536
+ previewUrl: v2.optional(v2.string()),
537
+ nextSteps: v2.optional(v2.array(v2.string())),
538
+ /** Tarball location, relative to the index URL. */
539
+ file: v2.string(),
540
+ sha256: v2.pipe(v2.string(), v2.regex(/^[0-9a-f]{64}$/)),
541
+ size: v2.optional(v2.number()),
542
+ version: v2.optional(v2.string())
543
+ });
544
+ var indexSchema = v2.object({
545
+ schemaVersion: v2.literal(1),
546
+ templates: v2.array(v2.unknown())
547
+ });
548
+ function cacheRoot() {
549
+ return path4.join(configDir(), CACHE_DIR_NAME);
550
+ }
551
+ function indexCachePath() {
552
+ return path4.join(cacheRoot(), INDEX_CACHE_FILE);
553
+ }
554
+ function readCachedIndex(url) {
555
+ const file = indexCachePath();
556
+ if (!fs5.existsSync(file)) return null;
557
+ try {
558
+ const cached2 = JSON.parse(fs5.readFileSync(file, "utf8"));
559
+ if (cached2.url !== url) return null;
560
+ return cached2;
561
+ } catch {
562
+ return null;
563
+ }
564
+ }
565
+ function writeCachedIndex(cached2) {
566
+ fs5.mkdirSync(cacheRoot(), { recursive: true });
567
+ fs5.writeFileSync(indexCachePath(), JSON.stringify(cached2, null, 2));
568
+ }
569
+ function parseTemplateIndex(text18, url) {
570
+ let parsed;
571
+ try {
572
+ parsed = JSON.parse(text18);
573
+ } catch (e) {
574
+ throw new Error(`Template index at ${url} is not valid JSON: ${e.message}`);
575
+ }
576
+ const doc = v2.safeParse(indexSchema, parsed);
577
+ if (!doc.success) {
578
+ throw new Error(`Template index at ${url} has an unsupported format`);
579
+ }
580
+ const templates = [];
581
+ let skipped = 0;
582
+ for (const raw of doc.output.templates) {
583
+ const entry = v2.safeParse(entrySchema, raw);
584
+ if (entry.success) templates.push(entry.output);
585
+ else skipped++;
586
+ }
587
+ return { url, templates, skipped };
588
+ }
589
+ function isFileUrl(url) {
590
+ return url.startsWith("file:");
591
+ }
592
+ async function readBytes(url, options) {
593
+ if (isFileUrl(url)) {
594
+ return new Uint8Array(fs5.readFileSync(fileURLToPath(url)));
595
+ }
596
+ const res = await fetch(url, {
597
+ headers: options.headers,
598
+ signal: AbortSignal.timeout(options.timeoutMs)
599
+ });
600
+ if (!res.ok) {
601
+ throw new Error(`${res.status} ${res.statusText}`.trim());
602
+ }
603
+ return new Uint8Array(await res.arrayBuffer());
604
+ }
605
+ async function fetchTemplateIndex(url, options = {}) {
606
+ const now = options.now ?? Date.now();
607
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
608
+ const cached2 = options.noCache ? null : readCachedIndex(url);
609
+ if (cached2 && now - cached2.fetchedAt < INDEX_CACHE_TTL_MS && !isFileUrl(url)) {
610
+ return { index: cached2.index, stale: false };
611
+ }
612
+ try {
613
+ const bytes = await readBytes(url, { timeoutMs, headers: options.headers });
614
+ const index = parseTemplateIndex(Buffer.from(bytes).toString("utf8"), url);
615
+ if (!options.noCache && !isFileUrl(url)) {
616
+ writeCachedIndex({ url, fetchedAt: now, index });
617
+ }
618
+ return { index, stale: false };
619
+ } catch (e) {
620
+ const reason = e.message;
621
+ if (cached2) return { index: cached2.index, stale: true, reason };
622
+ return { index: null, stale: false, reason };
623
+ }
624
+ }
625
+ function resolveDownloadUrl(entry, indexUrl) {
626
+ return new URL(entry.file, indexUrl).href;
627
+ }
628
+ function sha256(bytes) {
629
+ return createHash("sha256").update(bytes).digest("hex");
630
+ }
631
+ function tarballCachePath(entry) {
632
+ return path4.join(
633
+ cacheRoot(),
634
+ TARBALL_CACHE_DIR,
635
+ `${entry.name}-${entry.sha256.slice(0, 12)}.tgz`
636
+ );
637
+ }
638
+ async function downloadTemplate(entry, indexUrl, options = {}) {
639
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS * 6;
640
+ const cacheFile = tarballCachePath(entry);
641
+ let haveTarball = false;
642
+ if (fs5.existsSync(cacheFile)) {
643
+ const cached2 = new Uint8Array(fs5.readFileSync(cacheFile));
644
+ haveTarball = sha256(cached2) === entry.sha256;
645
+ }
646
+ if (!haveTarball) {
647
+ const url = resolveDownloadUrl(entry, indexUrl);
648
+ let fetched;
649
+ try {
650
+ fetched = await readBytes(url, { timeoutMs, headers: options.headers });
651
+ } catch (e) {
652
+ throw new Error(`Could not download template ${entry.name}: ${e.message}`);
653
+ }
654
+ const digest = sha256(fetched);
655
+ if (digest !== entry.sha256) {
656
+ throw new Error(
657
+ `Downloaded template ${entry.name} did not match its checksum (expected ${entry.sha256}, got ${digest}). Try again, or set VELA_TEMPLATE_INDEX_URL to a registry you trust.`
658
+ );
659
+ }
660
+ fs5.mkdirSync(path4.dirname(cacheFile), { recursive: true });
661
+ fs5.writeFileSync(cacheFile, fetched);
662
+ }
663
+ const dir = fs5.mkdtempSync(path4.join(os2.tmpdir(), `vela-template-${entry.name}-`));
664
+ try {
665
+ await tar.extract({ file: cacheFile, cwd: dir, strip: 1 });
666
+ } catch (e) {
667
+ fs5.rmSync(dir, { recursive: true, force: true });
668
+ throw new Error(`Could not unpack template ${entry.name}: ${e.message}`);
669
+ }
670
+ return dir;
671
+ }
672
+
673
+ // src/lib/templates.ts
426
674
  var TEMPLATE_MANIFEST = "template.json";
427
675
  var DEFAULT_TEMPLATE = "minimal";
676
+ var DEFAULT_CATEGORY = "starter";
428
677
  var cached;
429
678
  function templatesDir() {
430
- let dir = path2.dirname(fileURLToPath(import.meta.url));
431
- const { root } = path2.parse(dir);
679
+ let dir = path5.dirname(fileURLToPath2(import.meta.url));
680
+ const { root } = path5.parse(dir);
432
681
  while (dir !== root) {
433
- const candidate = path2.join(dir, "templates");
682
+ const candidate = path5.join(dir, "templates");
434
683
  if (holdsManifest(candidate)) return candidate;
435
- dir = path2.dirname(dir);
684
+ dir = path5.dirname(dir);
436
685
  }
437
686
  throw new Error("Could not locate the templates directory");
438
687
  }
439
688
  function holdsManifest(dir) {
440
- if (!fs3.existsSync(dir)) return false;
441
- return fs3.readdirSync(dir, { withFileTypes: true }).some(
442
- (entry) => entry.isDirectory() && fs3.existsSync(path2.join(dir, entry.name, TEMPLATE_MANIFEST))
689
+ if (!fs6.existsSync(dir)) return false;
690
+ return fs6.readdirSync(dir, { withFileTypes: true }).some(
691
+ (entry) => entry.isDirectory() && fs6.existsSync(path5.join(dir, entry.name, TEMPLATE_MANIFEST))
443
692
  );
444
693
  }
445
694
  function listProjectTemplates() {
446
695
  if (cached) return cached;
447
696
  const root = templatesDir();
448
- cached = fs3.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readManifest(root, entry.name)).filter((template) => template !== void 0).sort((a, b) => a.name.localeCompare(b.name));
697
+ cached = fs6.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readManifest(root, entry.name)).filter((template) => template !== void 0).sort((a, b) => a.name.localeCompare(b.name));
449
698
  return cached;
450
699
  }
451
700
  function projectTemplateNames(options = {}) {
@@ -458,12 +707,84 @@ function findProjectTemplate(name) {
458
707
  if (!template) throw new Error(`Template not found: ${name}`);
459
708
  return template;
460
709
  }
710
+ async function listAllTemplates(options = {}) {
711
+ const indexUrl = options.indexUrl ?? TEMPLATE_INDEX_URL;
712
+ const builtin = listProjectTemplates();
713
+ const names = new Set(builtin.map((template) => template.name));
714
+ const templates = [...builtin];
715
+ const result = await fetchTemplateIndex(indexUrl);
716
+ for (const entry of result.index?.templates ?? []) {
717
+ if (names.has(entry.name)) continue;
718
+ names.add(entry.name);
719
+ templates.push({
720
+ name: entry.name,
721
+ description: entry.description,
722
+ backend: entry.backend,
723
+ source: "remote",
724
+ category: entry.category ?? DEFAULT_CATEGORY,
725
+ title: entry.title,
726
+ tags: entry.tags,
727
+ price: entry.price,
728
+ nextSteps: entry.nextSteps,
729
+ entry,
730
+ indexUrl
731
+ });
732
+ }
733
+ templates.sort(compareTemplates);
734
+ return result.index ? { templates } : { templates, registryError: result.reason };
735
+ }
736
+ function compareTemplates(a, b) {
737
+ if (a.category !== b.category) {
738
+ if (a.category === DEFAULT_CATEGORY) return -1;
739
+ if (b.category === DEFAULT_CATEGORY) return 1;
740
+ return a.category.localeCompare(b.category);
741
+ }
742
+ return a.name.localeCompare(b.name);
743
+ }
744
+ function findTemplate(listing, name) {
745
+ const template = listing.templates.find((candidate) => candidate.name === name);
746
+ if (!template) throw new Error(`Template not found: ${name}`);
747
+ return template;
748
+ }
749
+ function templateChoicesMessage(templates) {
750
+ const groups = /* @__PURE__ */ new Map();
751
+ for (const template of [...templates].sort(compareTemplates)) {
752
+ const names = groups.get(template.category) ?? [];
753
+ names.push(template.name);
754
+ groups.set(template.category, names);
755
+ }
756
+ return [...groups].map(([category, names]) => `${category}: ${names.join(", ")}`).join("; ");
757
+ }
758
+ async function resolveTemplate(template) {
759
+ if (!("entry" in template)) {
760
+ return { ...template, cleanup() {
761
+ } };
762
+ }
763
+ const { entry, indexUrl, ...info } = template;
764
+ const dir = await downloadTemplate(entry, indexUrl);
765
+ return {
766
+ ...info,
767
+ dir,
768
+ cleanup() {
769
+ fs6.rmSync(dir, { recursive: true, force: true });
770
+ }
771
+ };
772
+ }
773
+ function copyTemplate(template, target) {
774
+ fs6.mkdirSync(target, { recursive: true });
775
+ fs6.cpSync(template.dir, target, {
776
+ recursive: true,
777
+ // The manifest describes the template to the CLI; it isn't part of the project.
778
+ filter: (src) => path5.basename(src) !== ".DS_Store" && path5.relative(template.dir, src) !== TEMPLATE_MANIFEST
779
+ });
780
+ restoreTemplateNames(target);
781
+ }
461
782
  function readManifest(root, name) {
462
- const manifestPath = path2.join(root, name, TEMPLATE_MANIFEST);
463
- if (!fs3.existsSync(manifestPath)) return void 0;
783
+ const manifestPath = path5.join(root, name, TEMPLATE_MANIFEST);
784
+ if (!fs6.existsSync(manifestPath)) return void 0;
464
785
  let parsed;
465
786
  try {
466
- parsed = JSON.parse(fs3.readFileSync(manifestPath, "utf8"));
787
+ parsed = JSON.parse(fs6.readFileSync(manifestPath, "utf8"));
467
788
  } catch (e) {
468
789
  throw new Error(
469
790
  `Template ${name} has an unreadable ${TEMPLATE_MANIFEST}: ${e.message}`
@@ -479,14 +800,28 @@ function readManifest(root, name) {
479
800
  name,
480
801
  description: manifest.description,
481
802
  backend: manifest.backend,
482
- dir: path2.join(root, name)
803
+ source: "builtin",
804
+ category: optionalString(manifest.category) ?? DEFAULT_CATEGORY,
805
+ title: optionalString(manifest.title),
806
+ tags: optionalStringArray(manifest.tags),
807
+ price: typeof manifest.price === "number" ? manifest.price : void 0,
808
+ nextSteps: optionalStringArray(manifest.nextSteps),
809
+ dir: path5.join(root, name)
483
810
  };
484
811
  }
812
+ function optionalString(value) {
813
+ return typeof value === "string" && value.length > 0 ? value : void 0;
814
+ }
815
+ function optionalStringArray(value) {
816
+ if (!Array.isArray(value)) return void 0;
817
+ const strings = value.filter((item) => typeof item === "string");
818
+ return strings.length > 0 ? strings : void 0;
819
+ }
485
820
 
486
821
  // src/lib/package-manager.ts
487
- import fs4 from "node:fs";
488
- import path3 from "node:path";
489
- import process4 from "node:process";
822
+ import fs7 from "node:fs";
823
+ import path6 from "node:path";
824
+ import process5 from "node:process";
490
825
  import { exec } from "tinyexec";
491
826
  import { Option } from "commander";
492
827
  import * as p2 from "@clack/prompts";
@@ -502,7 +837,7 @@ var installOption = new Option(
502
837
  "installs dependencies with a specified package manager"
503
838
  ).choices(AGENT_NAMES);
504
839
  function getUserAgent() {
505
- const userAgent = process4.env.npm_config_user_agent;
840
+ const userAgent = process5.env.npm_config_user_agent;
506
841
  if (!userAgent) return void 0;
507
842
  const pmSpec = userAgent.split(" ")[0];
508
843
  const separatorPos = pmSpec.lastIndexOf("/");
@@ -512,7 +847,7 @@ function getUserAgent() {
512
847
  async function packageManagerPrompt(cwd) {
513
848
  const detected = await detect({ cwd });
514
849
  const agent = detected?.name ?? getUserAgent();
515
- if (!process4.stdout.isTTY) return agent;
850
+ if (!process5.stdout.isTTY) return agent;
516
851
  const options = [
517
852
  { label: "None", value: void 0 },
518
853
  ...AGENT_NAMES.map((pm2) => ({ value: pm2, label: pm2 }))
@@ -524,14 +859,14 @@ async function packageManagerPrompt(cwd) {
524
859
  });
525
860
  if (p2.isCancel(pm)) {
526
861
  p2.cancel("Operation cancelled.");
527
- process4.exit(1);
862
+ process5.exit(1);
528
863
  }
529
864
  return pm;
530
865
  }
531
866
  async function installDependencies(agent, cwd) {
532
867
  const task = p2.taskLog({
533
868
  title: `Installing dependencies with ${agent}...`,
534
- limit: Math.ceil(process4.stdout.rows / 2),
869
+ limit: Math.ceil(process5.stdout.rows / 2),
535
870
  spacing: 0,
536
871
  retainLog: true
537
872
  });
@@ -548,14 +883,14 @@ async function installDependencies(agent, cwd) {
548
883
  } catch {
549
884
  task.error("Failed to install dependencies");
550
885
  p2.cancel("Operation failed.");
551
- process4.exit(2);
886
+ process5.exit(2);
552
887
  }
553
888
  }
554
889
  function addPnpmBuildDependencies(cwd, packageManager, allowedPackages) {
555
890
  if (!packageManager || packageManager !== "pnpm") return;
556
- const pkgPath = path3.join(cwd, "package.json");
557
- if (!fs4.existsSync(pkgPath)) return;
558
- const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
891
+ const pkgPath = path6.join(cwd, "package.json");
892
+ if (!fs7.existsSync(pkgPath)) return;
893
+ const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
559
894
  pkg.pnpm ??= {};
560
895
  pkg.pnpm.onlyBuiltDependencies ??= [];
561
896
  for (const name of allowedPackages) {
@@ -563,14 +898,14 @@ function addPnpmBuildDependencies(cwd, packageManager, allowedPackages) {
563
898
  pkg.pnpm.onlyBuiltDependencies.push(name);
564
899
  }
565
900
  }
566
- fs4.writeFileSync(pkgPath, JSON.stringify(pkg, null, " ") + "\n");
901
+ fs7.writeFileSync(pkgPath, JSON.stringify(pkg, null, " ") + "\n");
567
902
  }
568
903
 
569
904
  // src/lib/pocketbase.ts
570
- import fs5 from "node:fs";
905
+ import fs8 from "node:fs";
571
906
  import net from "node:net";
572
- import path4 from "node:path";
573
- import process5 from "node:process";
907
+ import path7 from "node:path";
908
+ import process6 from "node:process";
574
909
  import { createRequire } from "node:module";
575
910
  import { spawn } from "node:child_process";
576
911
  import PocketBase from "pocketbase";
@@ -682,9 +1017,9 @@ async function authWithRetries(pb, email3, password11, attempts = 3) {
682
1017
  }
683
1018
  }
684
1019
  function getPocketbaseMetadata(cwd) {
685
- const metadataPath = path4.join(cwd, "node_modules", ".vite", "_pocketbase_metadata.json");
686
- if (fs5.existsSync(metadataPath)) {
687
- return JSON.parse(fs5.readFileSync(metadataPath, "utf8"));
1020
+ const metadataPath = path7.join(cwd, "node_modules", ".vite", "_pocketbase_metadata.json");
1021
+ if (fs8.existsSync(metadataPath)) {
1022
+ return JSON.parse(fs8.readFileSync(metadataPath, "utf8"));
688
1023
  }
689
1024
  return null;
690
1025
  }
@@ -697,12 +1032,12 @@ async function execPackageBin(cwd, args, stdio = "pipe") {
697
1032
  return x(command, resolvedArgs, { nodeOptions: { cwd, stdio }, throwOnError: true });
698
1033
  }
699
1034
  async function withPocketbase(cwd, fn, creds) {
700
- const dir = path4.join(cwd, DATA_DIR);
701
- const migrationsDir = path4.join(cwd, MIGRATIONS_DIR);
1035
+ const dir = path7.join(cwd, DATA_DIR);
1036
+ const migrationsDir = path7.join(cwd, MIGRATIONS_DIR);
702
1037
  const host = "localhost";
703
- const email3 = creds?.email ?? process5.env.POCKETBASE_SUPERUSER_EMAIL;
704
- const password11 = creds?.password ?? process5.env.POCKETBASE_SUPERUSER_PASSWORD;
705
- if (!fs5.existsSync(dir)) {
1038
+ const email3 = creds?.email ?? process6.env.POCKETBASE_SUPERUSER_EMAIL;
1039
+ const password11 = creds?.password ?? process6.env.POCKETBASE_SUPERUSER_PASSWORD;
1040
+ if (!fs8.existsSync(dir)) {
706
1041
  throw new Error("PocketBase data directory does not exist");
707
1042
  }
708
1043
  const metadata = getPocketbaseMetadata(cwd);
@@ -727,10 +1062,10 @@ async function withPocketbase(cwd, fn, creds) {
727
1062
  }
728
1063
  }
729
1064
  async function createSuperuser(cwd, email3, password11) {
730
- const dir = path4.join(cwd, DATA_DIR);
731
- const migrationsDir = path4.join(cwd, MIGRATIONS_DIR);
732
- fs5.mkdirSync(dir, { recursive: true });
733
- fs5.mkdirSync(migrationsDir, { recursive: true });
1065
+ const dir = path7.join(cwd, DATA_DIR);
1066
+ const migrationsDir = path7.join(cwd, MIGRATIONS_DIR);
1067
+ fs8.mkdirSync(dir, { recursive: true });
1068
+ fs8.mkdirSync(migrationsDir, { recursive: true });
734
1069
  await execPackageBin(
735
1070
  cwd,
736
1071
  [
@@ -755,8 +1090,8 @@ async function launchPocketbase(cwd, {
755
1090
  password: password11
756
1091
  }) {
757
1092
  const host = "localhost";
758
- fs5.mkdirSync(dir, { recursive: true });
759
- fs5.mkdirSync(migrationsDir, { recursive: true });
1093
+ fs8.mkdirSync(dir, { recursive: true });
1094
+ fs8.mkdirSync(migrationsDir, { recursive: true });
760
1095
  await execPackageBin(
761
1096
  cwd,
762
1097
  [
@@ -795,11 +1130,11 @@ function pocketbaseVersion() {
795
1130
  return pkg.version;
796
1131
  }
797
1132
  async function ensureSuperuser(cwd) {
798
- const email3 = process5.env.POCKETBASE_SUPERUSER_EMAIL;
799
- const password11 = process5.env.POCKETBASE_SUPERUSER_PASSWORD;
1133
+ const email3 = process6.env.POCKETBASE_SUPERUSER_EMAIL;
1134
+ const password11 = process6.env.POCKETBASE_SUPERUSER_PASSWORD;
800
1135
  if (!email3 || !password11) return;
801
- const dir = path4.join(cwd, DATA_DIR);
802
- if (!fs5.existsSync(dir)) return;
1136
+ const dir = path7.join(cwd, DATA_DIR);
1137
+ if (!fs8.existsSync(dir)) return;
803
1138
  const { getBinaryPath } = await import("pocketbase-server");
804
1139
  await x(
805
1140
  getBinaryPath(),
@@ -807,7 +1142,7 @@ async function ensureSuperuser(cwd) {
807
1142
  "--dir",
808
1143
  dir,
809
1144
  "--migrationsDir",
810
- path4.join(cwd, MIGRATIONS_DIR),
1145
+ path7.join(cwd, MIGRATIONS_DIR),
811
1146
  "superuser",
812
1147
  "upsert",
813
1148
  email3,
@@ -818,8 +1153,8 @@ async function ensureSuperuser(cwd) {
818
1153
  }
819
1154
 
820
1155
  // src/lib/env.ts
821
- import fs6 from "node:fs";
822
- import path5 from "node:path";
1156
+ import fs9 from "node:fs";
1157
+ import path8 from "node:path";
823
1158
  function addEnvVar(content, key, value) {
824
1159
  if (content.includes(`${key}=`)) return content;
825
1160
  return appendLine(content, `${key}=${value}`);
@@ -834,11 +1169,11 @@ function appendLine(existing, line) {
834
1169
  return withNewline + line + "\n";
835
1170
  }
836
1171
  function writeEnvFile(cwd, vars, comments = []) {
837
- const envPath = path5.join(cwd, ".env");
838
- let content = fs6.existsSync(envPath) ? fs6.readFileSync(envPath, "utf8") : "";
1172
+ const envPath = path8.join(cwd, ".env");
1173
+ let content = fs9.existsSync(envPath) ? fs9.readFileSync(envPath, "utf8") : "";
839
1174
  for (const comment of comments) content = addEnvComment(content, comment);
840
1175
  for (const [key, value] of Object.entries(vars)) content = addEnvVar(content, key, value);
841
- fs6.writeFileSync(envPath, content);
1176
+ fs9.writeFileSync(envPath, content);
842
1177
  }
843
1178
  function upsertEnvVar(content, key, value) {
844
1179
  const line = `${key}=${quoteEnvValue(value)}`;
@@ -871,7 +1206,7 @@ function quoteEnvValue(value) {
871
1206
  }
872
1207
 
873
1208
  // src/lib/app-css.ts
874
- import fs7 from "node:fs";
1209
+ import fs10 from "node:fs";
875
1210
  var SHADCN_TAILWIND_CSS = "shadcn-svelte/tailwind.css";
876
1211
  var SHADCN_TAILWIND_IMPORT = `@import '${SHADCN_TAILWIND_CSS}';`;
877
1212
  function hasShadcnImport(css) {
@@ -897,21 +1232,21 @@ ${css}`;
897
1232
  return lines.join("\n");
898
1233
  }
899
1234
  function ensureShadcnImport(appCssPath) {
900
- if (!fs7.existsSync(appCssPath)) return false;
901
- const css = fs7.readFileSync(appCssPath, "utf8");
1235
+ if (!fs10.existsSync(appCssPath)) return false;
1236
+ const css = fs10.readFileSync(appCssPath, "utf8");
902
1237
  if (hasShadcnImport(css)) return false;
903
- fs7.writeFileSync(appCssPath, insertShadcnImport(css));
1238
+ fs10.writeFileSync(appCssPath, insertShadcnImport(css));
904
1239
  return true;
905
1240
  }
906
1241
 
907
1242
  // src/lib/components-json.ts
908
- import fs8 from "node:fs";
909
- import path6 from "node:path";
1243
+ import fs11 from "node:fs";
1244
+ import path9 from "node:path";
910
1245
  function readComponentsJson(root) {
911
- const file = path6.join(root, "components.json");
912
- if (!fs8.existsSync(file)) return void 0;
1246
+ const file = path9.join(root, "components.json");
1247
+ if (!fs11.existsSync(file)) return void 0;
913
1248
  try {
914
- const parsed = JSON.parse(fs8.readFileSync(file, "utf8"));
1249
+ const parsed = JSON.parse(fs11.readFileSync(file, "utf8"));
915
1250
  return parsed && typeof parsed === "object" ? parsed : void 0;
916
1251
  } catch {
917
1252
  return void 0;
@@ -933,12 +1268,12 @@ function componentsJsonHints(config) {
933
1268
  }
934
1269
 
935
1270
  // src/lib/config-merge.ts
936
- import fs10 from "node:fs";
937
- import path8 from "node:path";
1271
+ import fs13 from "node:fs";
1272
+ import path11 from "node:path";
938
1273
 
939
1274
  // src/lib/config-target.ts
940
- import fs9 from "node:fs";
941
- import path7 from "node:path";
1275
+ import fs12 from "node:fs";
1276
+ import path10 from "node:path";
942
1277
  import {
943
1278
  Project,
944
1279
  QuoteKind,
@@ -958,8 +1293,8 @@ var SVELTE_CONFIG_CANDIDATES = [
958
1293
  ];
959
1294
  function probeFirstExisting(root, candidates) {
960
1295
  for (const rel of candidates) {
961
- const abs = path7.join(root, rel);
962
- if (fs9.existsSync(abs)) return abs;
1296
+ const abs = path10.join(root, rel);
1297
+ if (fs12.existsSync(abs)) return abs;
963
1298
  }
964
1299
  return null;
965
1300
  }
@@ -1035,7 +1370,7 @@ function mergeSvelteConfig(projectRoot) {
1035
1370
  };
1036
1371
  }
1037
1372
  function mergeRunesIntoViteArg(vite, arg) {
1038
- const file = path8.basename(vite.filePath);
1373
+ const file = path11.basename(vite.filePath);
1039
1374
  const compilerOptions = getOrCreateObjectLiteralProperty(arg, "compilerOptions", "{}");
1040
1375
  if (!compilerOptions) {
1041
1376
  return {
@@ -1054,8 +1389,8 @@ function mergeRunesIntoViteArg(vite, arg) {
1054
1389
  return { applied: true, reason: "added runes compilerOption", file };
1055
1390
  }
1056
1391
  function mergeRunesIntoSvelteConfig(filePath) {
1057
- const file = path8.basename(filePath);
1058
- const original = fs10.readFileSync(filePath, "utf8");
1392
+ const file = path11.basename(filePath);
1393
+ const original = fs13.readFileSync(filePath, "utf8");
1059
1394
  if (/runes\s*:/m.test(original)) {
1060
1395
  return { applied: false, reason: "runes already configured", file };
1061
1396
  }
@@ -1078,11 +1413,11 @@ function mergeRunesIntoSvelteConfig(filePath) {
1078
1413
  }
1079
1414
  const insertAt = anchor.index + anchor[0].length;
1080
1415
  const updated = original.slice(0, insertAt) + RUNES_SNIPPET + original.slice(insertAt);
1081
- fs10.writeFileSync(filePath, updated);
1416
+ fs13.writeFileSync(filePath, updated);
1082
1417
  return { applied: true, reason: "added runes compilerOption", file };
1083
1418
  }
1084
1419
  function mergeViteConfig(filePath) {
1085
- if (!fs10.existsSync(filePath)) {
1420
+ if (!fs13.existsSync(filePath)) {
1086
1421
  return {
1087
1422
  applied: false,
1088
1423
  reason: "vite.config.ts not found",
@@ -1090,7 +1425,7 @@ function mergeViteConfig(filePath) {
1090
1425
  // then add tailwindcss() to the plugins array`
1091
1426
  };
1092
1427
  }
1093
- const original = fs10.readFileSync(filePath, "utf8");
1428
+ const original = fs13.readFileSync(filePath, "utf8");
1094
1429
  if (original.includes("@tailwindcss/vite")) {
1095
1430
  return { applied: false, reason: "tailwindcss plugin already present" };
1096
1431
  }
@@ -1109,14 +1444,14 @@ function mergeViteConfig(filePath) {
1109
1444
  const trailing = withImport.slice(insertAt);
1110
1445
  const prefix = /^\s*\]/.test(trailing) ? "tailwindcss()" : "tailwindcss(), ";
1111
1446
  const updated = withImport.slice(0, insertAt) + prefix + withImport.slice(insertAt);
1112
- fs10.writeFileSync(filePath, updated);
1447
+ fs13.writeFileSync(filePath, updated);
1113
1448
  return { applied: true, reason: "added @tailwindcss/vite plugin" };
1114
1449
  }
1115
1450
  function mergeTsconfig(filePath) {
1116
- if (!fs10.existsSync(filePath)) {
1451
+ if (!fs13.existsSync(filePath)) {
1117
1452
  return { applied: false, reason: "tsconfig.json not found" };
1118
1453
  }
1119
- const original = fs10.readFileSync(filePath, "utf8");
1454
+ const original = fs13.readFileSync(filePath, "utf8");
1120
1455
  if (/rewriteRelativeImportExtensions/.test(original)) {
1121
1456
  return { applied: false, reason: "rewriteRelativeImportExtensions already set" };
1122
1457
  }
@@ -1132,7 +1467,7 @@ function mergeTsconfig(filePath) {
1132
1467
  const indent = detectIndent(original, insertAt);
1133
1468
  const updated = original.slice(0, insertAt) + `
1134
1469
  ${indent}"rewriteRelativeImportExtensions": true,` + original.slice(insertAt);
1135
- fs10.writeFileSync(filePath, updated);
1470
+ fs13.writeFileSync(filePath, updated);
1136
1471
  return { applied: true, reason: "added rewriteRelativeImportExtensions" };
1137
1472
  }
1138
1473
  var GITIGNORE_ENTRIES = [
@@ -1144,7 +1479,7 @@ var GITIGNORE_ENTRIES = [
1144
1479
  "vite.config.ts.timestamp-*"
1145
1480
  ];
1146
1481
  function mergeGitignore(filePath) {
1147
- const existing = fs10.existsSync(filePath) ? fs10.readFileSync(filePath, "utf8") : "";
1482
+ const existing = fs13.existsSync(filePath) ? fs13.readFileSync(filePath, "utf8") : "";
1148
1483
  const lines = existing.split("\n").map((l) => l.trim());
1149
1484
  const missing = GITIGNORE_ENTRIES.filter((entry) => !lines.includes(entry));
1150
1485
  if (missing.length === 0) {
@@ -1153,7 +1488,7 @@ function mergeGitignore(filePath) {
1153
1488
  const needsNewline = existing.length > 0 && !existing.endsWith("\n");
1154
1489
  const appended = `${existing}${needsNewline ? "\n" : ""}${missing.join("\n")}
1155
1490
  `;
1156
- fs10.writeFileSync(filePath, appended);
1491
+ fs13.writeFileSync(filePath, appended);
1157
1492
  return { applied: true, reason: `added ${missing.length} gitignore entries` };
1158
1493
  }
1159
1494
  function addImport(source, importLine) {
@@ -1178,14 +1513,14 @@ function detectIndent(source, atOffset) {
1178
1513
  }
1179
1514
 
1180
1515
  // src/lib/scaffold-detect.ts
1181
- import fs11 from "node:fs";
1182
- import path9 from "node:path";
1516
+ import fs14 from "node:fs";
1517
+ import path12 from "node:path";
1183
1518
  var VANILLA_MARKER = "Welcome to SvelteKit";
1184
- var PAGE_REL = path9.join("src", "routes", "+page.svelte");
1519
+ var PAGE_REL = path12.join("src", "routes", "+page.svelte");
1185
1520
  function isVanillaRoutes(cwd) {
1186
- const pagePath = path9.join(cwd, PAGE_REL);
1187
- if (!fs11.existsSync(pagePath)) return false;
1188
- return fs11.readFileSync(pagePath, "utf8").includes(VANILLA_MARKER);
1521
+ const pagePath = path12.join(cwd, PAGE_REL);
1522
+ if (!fs14.existsSync(pagePath)) return false;
1523
+ return fs14.readFileSync(pagePath, "utf8").includes(VANILLA_MARKER);
1189
1524
  }
1190
1525
 
1191
1526
  // src/lib/result-report.ts
@@ -1232,62 +1567,16 @@ ${failure.message}` : headline);
1232
1567
  }
1233
1568
  }
1234
1569
 
1235
- // src/lib/template-files.ts
1236
- import fs12 from "node:fs";
1237
- import path10 from "node:path";
1238
- var PUBLISH_SAFE_NAMES = {
1239
- ".gitignore": "_gitignore",
1240
- ".npmrc": "_npmrc"
1241
- };
1242
- function templateName(projectRelPath) {
1243
- const safe = PUBLISH_SAFE_NAMES[path10.basename(projectRelPath)];
1244
- if (!safe) return projectRelPath;
1245
- const dir = path10.dirname(projectRelPath);
1246
- return dir === "." ? safe : path10.join(dir, safe);
1247
- }
1248
- function restoreTemplateNames(target) {
1249
- for (const [real, safe] of Object.entries(PUBLISH_SAFE_NAMES)) {
1250
- const from = path10.join(target, safe);
1251
- if (!fs12.existsSync(from)) continue;
1252
- fs12.renameSync(from, path10.join(target, real));
1253
- }
1254
- }
1255
- var TEMPLATE_SOURCE = /\.template\.([^.]+)$/;
1256
- function applyTemplateFiles(target, values) {
1257
- const written = [];
1258
- for (const source of findTemplateSources(target)) {
1259
- const raw = fs12.readFileSync(source, "utf8");
1260
- const dest = source.replace(TEMPLATE_SOURCE, ".$1");
1261
- fs12.writeFileSync(dest, fillTemplatePlaceholders(raw, values));
1262
- fs12.unlinkSync(source);
1263
- written.push(path10.relative(target, dest));
1264
- }
1265
- return written.sort();
1266
- }
1267
- function findTemplateSources(dir) {
1268
- const found = [];
1269
- for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
1270
- const full = path10.join(dir, entry.name);
1271
- if (entry.isDirectory()) {
1272
- if (entry.name === "node_modules" || entry.name === ".git") continue;
1273
- found.push(...findTemplateSources(full));
1274
- } else if (entry.isFile() && TEMPLATE_SOURCE.test(entry.name)) {
1275
- found.push(full);
1276
- }
1277
- }
1278
- return found;
1279
- }
1280
-
1281
1570
  // src/commands/bless.ts
1282
1571
  function optionsSchema() {
1283
1572
  const templates = projectTemplateNames({ backend: true });
1284
- return v2.strictObject({
1285
- install: v2.union([v2.boolean(), v2.picklist(AGENT_NAMES)], "must be a package manager"),
1286
- template: v2.optional(v2.picklist(templates, `must be one of: ${templates.join(", ")}`)),
1287
- email: v2.optional(v2.pipe(v2.string(), v2.email("must be a valid email address"))),
1288
- password: v2.optional(v2.pipe(v2.string(), v2.minLength(8, "must be at least 8 characters long"))),
1289
- skipRoutes: v2.optional(v2.boolean()),
1290
- forceRoutes: v2.optional(v2.boolean())
1573
+ return v3.strictObject({
1574
+ install: v3.union([v3.boolean(), v3.picklist(AGENT_NAMES)], "must be a package manager"),
1575
+ template: v3.optional(v3.picklist(templates, `must be one of: ${templates.join(", ")}`)),
1576
+ email: v3.optional(v3.pipe(v3.string(), v3.email("must be a valid email address"))),
1577
+ password: v3.optional(v3.pipe(v3.string(), v3.minLength(8, "must be at least 8 characters long"))),
1578
+ skipRoutes: v3.optional(v3.boolean()),
1579
+ forceRoutes: v3.optional(v3.boolean())
1291
1580
  });
1292
1581
  }
1293
1582
  var VELA_ONLY_FILES = [
@@ -1343,7 +1632,7 @@ async function blessProject(cwdArg, options) {
1343
1632
  {
1344
1633
  onCancel: () => {
1345
1634
  p4.cancel("Operation cancelled.");
1346
- process6.exit(0);
1635
+ process7.exit(0);
1347
1636
  }
1348
1637
  }
1349
1638
  );
@@ -1378,7 +1667,7 @@ async function blessProject(cwdArg, options) {
1378
1667
  printNextSteps(projectPath, packageManager);
1379
1668
  }
1380
1669
  function ensureShadcnCss(projectPath) {
1381
- if (ensureShadcnImport(path11.join(projectPath, "src", "app.css"))) {
1670
+ if (ensureShadcnImport(path13.join(projectPath, "src", "app.css"))) {
1382
1671
  p4.log.info(
1383
1672
  "src/app.css: added the shadcn-svelte/tailwind.css import its registry components rely on."
1384
1673
  );
@@ -1390,22 +1679,22 @@ function hintComponentsJson(projectPath) {
1390
1679
  for (const hint of componentsJsonHints(config)) p4.log.warn(hint);
1391
1680
  }
1392
1681
  function resolveProjectPath(cwdArg) {
1393
- const projectPath = path11.resolve(cwdArg);
1394
- if (!fs13.existsSync(projectPath)) {
1682
+ const projectPath = path13.resolve(cwdArg);
1683
+ if (!fs15.existsSync(projectPath)) {
1395
1684
  throw new Error(`Path does not exist: ${projectPath}`);
1396
1685
  }
1397
- if (!fs13.existsSync(path11.join(projectPath, "package.json"))) {
1686
+ if (!fs15.existsSync(path13.join(projectPath, "package.json"))) {
1398
1687
  throw new Error(`No package.json found at ${projectPath}`);
1399
1688
  }
1400
- if (!fs13.existsSync(path11.join(projectPath, "src", "routes"))) {
1689
+ if (!fs15.existsSync(path13.join(projectPath, "src", "routes"))) {
1401
1690
  throw new Error(`No src/routes directory found at ${projectPath}`);
1402
1691
  }
1403
1692
  return projectPath;
1404
1693
  }
1405
1694
  function assertNotAlreadyBlessed(projectPath) {
1406
- const hooksPath = path11.join(projectPath, "src", "hooks.server.ts");
1407
- if (!fs13.existsSync(hooksPath)) return;
1408
- const content = fs13.readFileSync(hooksPath, "utf8");
1695
+ const hooksPath = path13.join(projectPath, "src", "hooks.server.ts");
1696
+ if (!fs15.existsSync(hooksPath)) return;
1697
+ const content = fs15.readFileSync(hooksPath, "utf8");
1409
1698
  if (content.includes("@velastack/pocketbase")) {
1410
1699
  throw new Error(
1411
1700
  "This project already looks blessed (src/hooks.server.ts imports @velastack/pocketbase). Run `vela sync` instead."
@@ -1413,8 +1702,8 @@ function assertNotAlreadyBlessed(projectPath) {
1413
1702
  }
1414
1703
  }
1415
1704
  function mergeDependencies(projectPath, templateDir) {
1416
- const userPkgPath = path11.join(projectPath, "package.json");
1417
- const templatePkgPath = path11.join(templateDir, "package.template.json");
1705
+ const userPkgPath = path13.join(projectPath, "package.json");
1706
+ const templatePkgPath = path13.join(templateDir, "package.template.json");
1418
1707
  const userPkg = readPackageJson(userPkgPath);
1419
1708
  const appName = typeof userPkg.name === "string" ? userPkg.name : "sveltekit";
1420
1709
  const templatePkg = readTemplatePackageJson(templatePkgPath, {
@@ -1446,21 +1735,21 @@ ${lines.join("\n")}`);
1446
1735
  function copyVelaOnlyFiles(templateDir, projectPath) {
1447
1736
  const kept = [];
1448
1737
  for (const file of VELA_ONLY_FILES) {
1449
- const src = path11.join(templateDir, templateName(file.path));
1450
- const dest = path11.join(projectPath, file.path);
1451
- if (!fs13.existsSync(src)) continue;
1452
- if (fs13.existsSync(dest)) {
1738
+ const src = path13.join(templateDir, templateName(file.path));
1739
+ const dest = path13.join(projectPath, file.path);
1740
+ if (!fs15.existsSync(src)) continue;
1741
+ if (fs15.existsSync(dest)) {
1453
1742
  kept.push(file);
1454
1743
  continue;
1455
1744
  }
1456
- fs13.mkdirSync(path11.dirname(dest), { recursive: true });
1457
- fs13.copyFileSync(src, dest);
1745
+ fs15.mkdirSync(path13.dirname(dest), { recursive: true });
1746
+ fs15.copyFileSync(src, dest);
1458
1747
  }
1459
1748
  reportKeptFiles(kept);
1460
1749
  for (const rel of VELA_ONLY_DIRS) {
1461
- const src = path11.join(templateDir, rel);
1462
- const dest = path11.join(projectPath, rel);
1463
- if (!fs13.existsSync(src)) continue;
1750
+ const src = path13.join(templateDir, rel);
1751
+ const dest = path13.join(projectPath, rel);
1752
+ if (!fs15.existsSync(src)) continue;
1464
1753
  copyDirShallow(src, dest);
1465
1754
  }
1466
1755
  }
@@ -1474,15 +1763,15 @@ ${lines.join("\n")}`
1474
1763
  );
1475
1764
  }
1476
1765
  function copyDirShallow(src, dest) {
1477
- fs13.mkdirSync(dest, { recursive: true });
1478
- for (const entry of fs13.readdirSync(src, { withFileTypes: true })) {
1766
+ fs15.mkdirSync(dest, { recursive: true });
1767
+ for (const entry of fs15.readdirSync(src, { withFileTypes: true })) {
1479
1768
  if (entry.name === ".DS_Store") continue;
1480
- const srcChild = path11.join(src, entry.name);
1481
- const destChild = path11.join(dest, entry.name);
1769
+ const srcChild = path13.join(src, entry.name);
1770
+ const destChild = path13.join(dest, entry.name);
1482
1771
  if (entry.isDirectory()) {
1483
1772
  copyDirShallow(srcChild, destChild);
1484
- } else if (entry.isFile() && !fs13.existsSync(destChild)) {
1485
- fs13.copyFileSync(srcChild, destChild);
1773
+ } else if (entry.isFile() && !fs15.existsSync(destChild)) {
1774
+ fs15.copyFileSync(srcChild, destChild);
1486
1775
  }
1487
1776
  }
1488
1777
  }
@@ -1490,9 +1779,9 @@ function mergeConfigFiles(projectPath) {
1490
1779
  const runes = mergeSvelteConfig(projectPath);
1491
1780
  const outcomes = [
1492
1781
  [runes.file ?? "svelte.config", runes],
1493
- ["vite.config.ts", mergeViteConfig(path11.join(projectPath, "vite.config.ts"))],
1494
- ["tsconfig.json", mergeTsconfig(path11.join(projectPath, "tsconfig.json"))],
1495
- [".gitignore", mergeGitignore(path11.join(projectPath, ".gitignore"))]
1782
+ ["vite.config.ts", mergeViteConfig(path13.join(projectPath, "vite.config.ts"))],
1783
+ ["tsconfig.json", mergeTsconfig(path13.join(projectPath, "tsconfig.json"))],
1784
+ [".gitignore", mergeGitignore(path13.join(projectPath, ".gitignore"))]
1496
1785
  ];
1497
1786
  for (const [name, outcome] of outcomes) {
1498
1787
  if (outcome.applied) {
@@ -1509,14 +1798,14 @@ ${pc3.cyan(outcome.snippet)}`
1509
1798
  }
1510
1799
  }
1511
1800
  function mergeAppDts(templateDir, projectPath) {
1512
- const dest = path11.join(projectPath, "src", "app.d.ts");
1513
- const templateFile = path11.join(templateDir, "src", "app.d.ts");
1514
- if (!fs13.existsSync(dest)) {
1515
- if (!fs13.existsSync(templateFile)) return;
1516
- fs13.copyFileSync(templateFile, dest);
1801
+ const dest = path13.join(projectPath, "src", "app.d.ts");
1802
+ const templateFile = path13.join(templateDir, "src", "app.d.ts");
1803
+ if (!fs15.existsSync(dest)) {
1804
+ if (!fs15.existsSync(templateFile)) return;
1805
+ fs15.copyFileSync(templateFile, dest);
1517
1806
  return;
1518
1807
  }
1519
- const current = fs13.readFileSync(dest, "utf8");
1808
+ const current = fs15.readFileSync(dest, "utf8");
1520
1809
  if (current.includes("namespace Superforms")) return;
1521
1810
  const block = ` namespace Superforms {
1522
1811
  type Message = {
@@ -1535,7 +1824,7 @@ ${pc3.cyan(block)}`
1535
1824
  }
1536
1825
  const insertAt = match.index + match[0].length;
1537
1826
  const updated = current.slice(0, insertAt) + block + current.slice(insertAt);
1538
- fs13.writeFileSync(dest, updated);
1827
+ fs15.writeFileSync(dest, updated);
1539
1828
  }
1540
1829
  function maybeReplaceRoutes(projectPath, templateDir, options) {
1541
1830
  if (options.skipRoutes) {
@@ -1546,12 +1835,12 @@ function maybeReplaceRoutes(projectPath, templateDir, options) {
1546
1835
  p4.log.info("Leaving src/routes alone (looks customized).");
1547
1836
  return;
1548
1837
  }
1549
- const target = path11.join(projectPath, "src", "routes");
1550
- fs13.rmSync(target, { recursive: true, force: true });
1551
- const src = path11.join(templateDir, "src", "routes");
1552
- fs13.cpSync(src, target, {
1838
+ const target = path13.join(projectPath, "src", "routes");
1839
+ fs15.rmSync(target, { recursive: true, force: true });
1840
+ const src = path13.join(templateDir, "src", "routes");
1841
+ fs15.cpSync(src, target, {
1553
1842
  recursive: true,
1554
- filter: (s) => path11.basename(s) !== ".DS_Store"
1843
+ filter: (s) => path13.basename(s) !== ".DS_Store"
1555
1844
  });
1556
1845
  p4.log.success("Replaced src/routes with the vela template.");
1557
1846
  }
@@ -1560,7 +1849,7 @@ function summarize(names) {
1560
1849
  return `${names.slice(0, 3).join(", ")}, and ${names.length - 3} more`;
1561
1850
  }
1562
1851
  function printNextSteps(projectPath, packageManager) {
1563
- const relative = path11.relative(process6.cwd(), projectPath);
1852
+ const relative = path13.relative(process7.cwd(), projectPath);
1564
1853
  const pm = packageManager ?? getUserAgent() ?? "npm";
1565
1854
  const nextSteps = [];
1566
1855
  if (relative !== "") {
@@ -1584,31 +1873,37 @@ function printNextSteps(projectPath, packageManager) {
1584
1873
  }
1585
1874
 
1586
1875
  // src/commands/create.ts
1587
- import fs14 from "node:fs";
1588
- import path12 from "node:path";
1589
- import process7 from "node:process";
1590
- import * as v3 from "valibot";
1876
+ import fs16 from "node:fs";
1877
+ import path14 from "node:path";
1878
+ import process8 from "node:process";
1879
+ import * as v4 from "valibot";
1591
1880
  import { Command as Command3 } from "commander";
1592
1881
  import * as p5 from "@clack/prompts";
1593
1882
  import { detect as detect3, resolveCommand as resolveCommand3 } from "package-manager-detector";
1594
- function optionsSchema2() {
1595
- const templates = projectTemplateNames();
1596
- return v3.strictObject({
1597
- install: v3.union([v3.boolean(), v3.picklist(AGENT_NAMES)], "must be a package manager"),
1598
- template: v3.optional(v3.picklist(templates, `must be one of: ${templates.join(", ")}`)),
1599
- name: v3.optional(v3.pipe(v3.string(), v3.trim(), v3.minLength(1, "must not be empty"))),
1600
- email: v3.optional(v3.pipe(v3.string(), v3.email("must be a valid email address"))),
1601
- password: v3.optional(v3.pipe(v3.string(), v3.minLength(8, "must be at least 8 characters long")))
1883
+ function optionsSchema2(listing) {
1884
+ const names = listing.templates.map((template) => template.name);
1885
+ let choices = `must be one of: ${templateChoicesMessage(listing.templates)}`;
1886
+ if (listing.registryError) {
1887
+ choices += ` (could not reach the template registry: ${listing.registryError})`;
1888
+ }
1889
+ return v4.strictObject({
1890
+ install: v4.union([v4.boolean(), v4.picklist(AGENT_NAMES)], "must be a package manager"),
1891
+ template: v4.optional(v4.picklist(names, choices)),
1892
+ name: v4.optional(v4.pipe(v4.string(), v4.trim(), v4.minLength(1, "must not be empty"))),
1893
+ email: v4.optional(v4.pipe(v4.string(), v4.email("must be a valid email address"))),
1894
+ password: v4.optional(v4.pipe(v4.string(), v4.minLength(8, "must be at least 8 characters long")))
1602
1895
  });
1603
1896
  }
1604
- var create = new Command3("create").description("scaffold a new velastack project").argument("[path]", "where the project will be created").option("--template <type>", "template to scaffold", "minimal").option("--no-install", "skip installing dependencies").option("--name <name>", "app name (used for emails, etc)").option("--email <email>", "email of the admin user").option("--password <password>", "password of the admin user").addOption(installOption).configureHelp(helpConfig).action((projectPath, rawOpts) => {
1897
+ var create = new Command3("create").description("scaffold a new velastack project").argument("[path]", "where the project will be created").option("--template <type>", "template to scaffold (built-in or from the registry)", "minimal").option("--no-install", "skip installing dependencies").option("--name <name>", "app name (used for emails, etc)").option("--email <email>", "email of the admin user").option("--password <password>", "password of the admin user").addOption(installOption).configureHelp(helpConfig).action((projectPath, rawOpts) => {
1605
1898
  return runCommand(async () => {
1606
- const options = parseOptions(optionsSchema2(), rawOpts);
1899
+ const listing = await listAllTemplates();
1900
+ const options = parseOptions(optionsSchema2(listing), rawOpts);
1607
1901
  const { directory, packageManager, name, template } = await createProject(
1608
1902
  projectPath,
1609
- options
1903
+ options,
1904
+ listing
1610
1905
  );
1611
- const relative = path12.relative(process7.cwd(), directory);
1906
+ const relative = path14.relative(process8.cwd(), directory);
1612
1907
  const pm = packageManager ?? (await detect3({ cwd: directory }))?.name ?? getUserAgent() ?? "npm";
1613
1908
  const nextSteps = [];
1614
1909
  if (relative !== "") {
@@ -1629,7 +1924,9 @@ var create = new Command3("create").description("scaffold a new velastack projec
1629
1924
  `\`${runDev.command} ${runDev.args.join(" ")}\` to start the dev server (Ctrl-C to stop)`
1630
1925
  );
1631
1926
  }
1632
- if (template.backend) {
1927
+ if (template.nextSteps) {
1928
+ nextSteps.push(...template.nextSteps);
1929
+ } else if (template.backend) {
1633
1930
  nextSteps.push("Run `vela generate scaffold <model>` to generate your first CRUD pages.");
1634
1931
  } else {
1635
1932
  nextSteps.push(
@@ -1644,12 +1941,12 @@ var create = new Command3("create").description("scaffold a new velastack projec
1644
1941
  });
1645
1942
  }, "Failed to create project.");
1646
1943
  });
1647
- async function createProject(cwdArg, options) {
1944
+ async function createProject(cwdArg, options, listing) {
1648
1945
  const onCancel2 = () => {
1649
1946
  p5.cancel("Operation cancelled.");
1650
- process7.exit(0);
1947
+ process8.exit(0);
1651
1948
  };
1652
- const template = findProjectTemplate(options.template ?? DEFAULT_TEMPLATE);
1949
+ const template = findTemplate(listing, options.template ?? DEFAULT_TEMPLATE);
1653
1950
  if (!template.backend && (options.email || options.password)) {
1654
1951
  throw new Error(
1655
1952
  `--email and --password don't apply to the ${template.name} template \u2014 it has no backend.`
@@ -1657,7 +1954,7 @@ async function createProject(cwdArg, options) {
1657
1954
  }
1658
1955
  let directory;
1659
1956
  if (cwdArg) {
1660
- directory = path12.resolve(cwdArg);
1957
+ directory = path14.resolve(cwdArg);
1661
1958
  } else {
1662
1959
  const answer = await p5.text({
1663
1960
  message: "Where would you like your project to be created?",
@@ -1665,16 +1962,16 @@ async function createProject(cwdArg, options) {
1665
1962
  defaultValue: "./"
1666
1963
  });
1667
1964
  if (p5.isCancel(answer)) onCancel2();
1668
- directory = path12.resolve(answer);
1965
+ directory = path14.resolve(answer);
1669
1966
  }
1670
- if (fs14.existsSync(directory) && fs14.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
1967
+ if (fs16.existsSync(directory) && fs16.readdirSync(directory).filter((f) => !f.startsWith(".git")).length > 0) {
1671
1968
  const force = await p5.confirm({
1672
1969
  message: "Directory not empty. Continue?",
1673
1970
  initialValue: false
1674
1971
  });
1675
1972
  if (p5.isCancel(force) || !force) onCancel2();
1676
1973
  }
1677
- const dirName = path12.basename(directory);
1974
+ const dirName = path14.basename(directory);
1678
1975
  const { name } = await p5.group(
1679
1976
  {
1680
1977
  name: () => {
@@ -1690,9 +1987,15 @@ async function createProject(cwdArg, options) {
1690
1987
  );
1691
1988
  const credentials = template.backend ? await promptCredentials(options, onCancel2) : void 0;
1692
1989
  const projectPath = directory;
1693
- copyTemplate(template, projectPath);
1694
- applyTemplateFiles(projectPath, { appName: name, cliVersion: package_default.version });
1695
- if (!fs14.existsSync(path12.join(projectPath, "package.json"))) {
1990
+ if (template.source === "remote") p5.log.step(`Downloading template ${template.name}...`);
1991
+ const resolved = await resolveTemplate(template);
1992
+ try {
1993
+ copyTemplate(resolved, projectPath);
1994
+ applyTemplateFiles(projectPath, { appName: name, cliVersion: package_default.version });
1995
+ } finally {
1996
+ resolved.cleanup();
1997
+ }
1998
+ if (!fs16.existsSync(path14.join(projectPath, "package.json"))) {
1696
1999
  throw new Error(`Template ${template.name} is missing package.template.json`);
1697
2000
  }
1698
2001
  p5.log.success("Project created");
@@ -1753,15 +2056,6 @@ function promptCredentials(options, onCancel2) {
1753
2056
  { onCancel: onCancel2 }
1754
2057
  );
1755
2058
  }
1756
- function copyTemplate(template, target) {
1757
- fs14.mkdirSync(target, { recursive: true });
1758
- fs14.cpSync(template.dir, target, {
1759
- recursive: true,
1760
- // The manifest describes the template to the CLI; it isn't part of the project.
1761
- filter: (src) => path12.basename(src) !== ".DS_Store" && path12.relative(template.dir, src) !== TEMPLATE_MANIFEST
1762
- });
1763
- restoreTemplateNames(target);
1764
- }
1765
2059
 
1766
2060
  // src/commands/generate.ts
1767
2061
  import { Command as Command9 } from "commander";
@@ -1771,11 +2065,11 @@ import { Command as Command4 } from "commander";
1771
2065
  import * as p11 from "@clack/prompts";
1772
2066
 
1773
2067
  // src/lib/pattern-runner.ts
1774
- import path13 from "node:path";
2068
+ import path15 from "node:path";
1775
2069
  import * as p6 from "@clack/prompts";
1776
2070
  import { bySlug } from "@velastack/patterns";
1777
2071
  function toRelative(root, filePath) {
1778
- return path13.isAbsolute(filePath) ? path13.relative(root, filePath) : filePath;
2072
+ return path15.isAbsolute(filePath) ? path15.relative(root, filePath) : filePath;
1779
2073
  }
1780
2074
  var isSuccess = (f) => (f.status ?? "success") === "success";
1781
2075
  async function runPattern(slug2, argv, input, report4) {
@@ -1842,57 +2136,22 @@ async function runPattern(slug2, argv, input, report4) {
1842
2136
  }
1843
2137
 
1844
2138
  // src/lib/ai-flow.ts
1845
- import fs17 from "node:fs";
1846
- import path16 from "node:path";
2139
+ import fs18 from "node:fs";
2140
+ import path17 from "node:path";
1847
2141
  import * as p10 from "@clack/prompts";
1848
2142
  import pc4 from "picocolors";
1849
2143
 
1850
- // src/lib/config.ts
1851
- import fs15 from "node:fs";
1852
- import os from "node:os";
1853
- import path14 from "node:path";
1854
- import process8 from "node:process";
1855
- var CONFIG_DIR = path14.join(os.homedir(), ".vela");
1856
- var CONFIG_PATH = path14.join(CONFIG_DIR, "config.json");
1857
- function readConfig() {
1858
- if (!fs15.existsSync(CONFIG_PATH)) return null;
1859
- try {
1860
- return JSON.parse(fs15.readFileSync(CONFIG_PATH, "utf8"));
1861
- } catch {
1862
- return null;
1863
- }
1864
- }
1865
- function writeConfig(config) {
1866
- fs15.mkdirSync(CONFIG_DIR, { recursive: true });
1867
- fs15.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
1868
- }
1869
- function clearConfig() {
1870
- if (fs15.existsSync(CONFIG_PATH)) fs15.unlinkSync(CONFIG_PATH);
1871
- }
1872
- function readApiKey() {
1873
- const fromEnv = process8.env.VELA_API_KEY?.trim();
1874
- if (fromEnv) return fromEnv;
1875
- return readConfig()?.apiKey ?? null;
1876
- }
1877
- function requireApiKey() {
1878
- const apiKey = readApiKey();
1879
- if (!apiKey) {
1880
- throw new Error("Not logged in. Run `vela login` to login, or set VELA_API_KEY.");
1881
- }
1882
- return apiKey;
1883
- }
1884
-
1885
2144
  // src/lib/project-config.ts
1886
- import fs16 from "node:fs";
1887
- import path15 from "node:path";
2145
+ import fs17 from "node:fs";
2146
+ import path16 from "node:path";
1888
2147
  function projectConfigPath(workspaceRootDir) {
1889
- return path15.join(workspaceRootDir, ".vela", "project.json");
2148
+ return path16.join(workspaceRootDir, ".vela", "project.json");
1890
2149
  }
1891
2150
  function readProjectConfig(workspaceRootDir) {
1892
2151
  const file = projectConfigPath(workspaceRootDir);
1893
- if (!fs16.existsSync(file)) return null;
2152
+ if (!fs17.existsSync(file)) return null;
1894
2153
  try {
1895
- const parsed = JSON.parse(fs16.readFileSync(file, "utf8"));
2154
+ const parsed = JSON.parse(fs17.readFileSync(file, "utf8"));
1896
2155
  if (typeof parsed.projectId !== "string" || typeof parsed.teamId !== "string" || typeof parsed.projectName !== "string") {
1897
2156
  return null;
1898
2157
  }
@@ -1907,15 +2166,15 @@ function readProjectConfig(workspaceRootDir) {
1907
2166
  }
1908
2167
  function writeProjectConfig(workspaceRootDir, config) {
1909
2168
  const file = projectConfigPath(workspaceRootDir);
1910
- fs16.mkdirSync(path15.dirname(file), { recursive: true });
2169
+ fs17.mkdirSync(path16.dirname(file), { recursive: true });
1911
2170
  let existing = {};
1912
- if (fs16.existsSync(file)) {
2171
+ if (fs17.existsSync(file)) {
1913
2172
  try {
1914
- existing = JSON.parse(fs16.readFileSync(file, "utf8"));
2173
+ existing = JSON.parse(fs17.readFileSync(file, "utf8"));
1915
2174
  } catch {
1916
2175
  }
1917
2176
  }
1918
- fs16.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
2177
+ fs17.writeFileSync(file, JSON.stringify({ ...existing, ...config }, null, 2) + "\n");
1919
2178
  }
1920
2179
 
1921
2180
  // src/lib/ai-client.ts
@@ -2189,11 +2448,11 @@ function specToArgv(spec) {
2189
2448
  return collectionSpecToArgv(spec);
2190
2449
  }
2191
2450
  function writeLayoutSidecar(workspaceRootDir, modelName, layout) {
2192
- const dir = path16.join(workspaceRootDir, "data", "ai-form-layouts");
2193
- fs17.mkdirSync(dir, { recursive: true });
2194
- const file = path16.join(dir, `${modelName}.json`);
2195
- fs17.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
2196
- return path16.relative(workspaceRootDir, file);
2451
+ const dir = path17.join(workspaceRootDir, "data", "ai-form-layouts");
2452
+ fs18.mkdirSync(dir, { recursive: true });
2453
+ const file = path17.join(dir, `${modelName}.json`);
2454
+ fs18.writeFileSync(file, JSON.stringify(layout, null, 2) + "\n");
2455
+ return path17.relative(workspaceRootDir, file);
2197
2456
  }
2198
2457
 
2199
2458
  // src/commands/generate/form.ts
@@ -2203,7 +2462,7 @@ var form = new Command4("form").description("generate a form from a model").argu
2203
2462
  ).option(
2204
2463
  "--ai <description>",
2205
2464
  "design the form with AI from a natural-language description (two stages: schema \u2192 layout)"
2206
- ).allowUnknownOption(true).configureHelp(helpConfig).action(
2465
+ ).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2207
2466
  (model, fields, options) => runCommand(async () => {
2208
2467
  let argv;
2209
2468
  let modelName;
@@ -2262,7 +2521,7 @@ var form = new Command4("form").description("generate a form from a model").argu
2262
2521
  // src/commands/generate/schema.ts
2263
2522
  import { Command as Command5 } from "commander";
2264
2523
  import * as p12 from "@clack/prompts";
2265
- var schema = new Command5("schema").description("generate a schema from a model").argument("[model]", "model name").argument("[fields...]", "field definitions").option("--ai <description>", "design the schema with AI from a natural-language description").allowUnknownOption(true).configureHelp(helpConfig).action(
2524
+ var schema = new Command5("schema").description("generate a schema from a model").argument("[model]", "model name").argument("[fields...]", "field definitions").option("--ai <description>", "design the schema with AI from a natural-language description").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2266
2525
  (model, fields, options) => runCommand(async () => {
2267
2526
  let argv;
2268
2527
  let modelName;
@@ -2306,7 +2565,7 @@ var schema = new Command5("schema").description("generate a schema from a model"
2306
2565
 
2307
2566
  // src/commands/generate/resource.ts
2308
2567
  import { Command as Command6 } from "commander";
2309
- var resource = new Command6("resource").description("generate a resource (model + CRUD pages)").argument("<model>", "model name").argument("[fields...]", "field definitions").allowUnknownOption(true).configureHelp(helpConfig).action(
2568
+ var resource = new Command6("resource").description("generate a resource (model + CRUD pages)").argument("<model>", "model name").argument("[fields...]", "field definitions").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2310
2569
  (model, fields) => runCommand(
2311
2570
  () => runPattern(
2312
2571
  "generate-resource",
@@ -2339,7 +2598,7 @@ var scaffold = new Command7("scaffold").description("generate a full CRUD scaffo
2339
2598
  ).option(
2340
2599
  "--ai <description>",
2341
2600
  "design the scaffold with AI from a natural-language description (two stages: schema \u2192 layout)"
2342
- ).allowUnknownOption(true).configureHelp(helpConfig).action(
2601
+ ).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2343
2602
  (model, fields, options) => runCommand(async () => {
2344
2603
  let argv;
2345
2604
  let modelName;
@@ -2398,7 +2657,7 @@ var scaffold = new Command7("scaffold").description("generate a full CRUD scaffo
2398
2657
 
2399
2658
  // src/commands/generate/migration.ts
2400
2659
  import { Command as Command8 } from "commander";
2401
- var migration = new Command8("migration").description("generate a migration for an existing collection").argument("<collection>", "collection name").argument("<op>", "operation (add, remove, rename, references)").argument("[args...]", 'operation arguments (e.g. "birthday:date")').allowUnknownOption(true).configureHelp(helpConfig).action(
2660
+ var migration = new Command8("migration").description("generate a migration for an existing collection").argument("<collection>", "collection name").argument("<op>", "operation (add, remove, rename, references)").argument("[args...]", 'operation arguments (e.g. "birthday:date")').allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2402
2661
  (collection, op, args) => runCommand(
2403
2662
  () => runPattern(
2404
2663
  "generate-migration",
@@ -2429,7 +2688,7 @@ import { Command as Command24 } from "commander";
2429
2688
 
2430
2689
  // src/commands/enable/auth.ts
2431
2690
  import { Command as Command10 } from "commander";
2432
- var auth = new Command10("auth").description("enable authentication (email/password + OAuth scaffold)").allowUnknownOption(true).configureHelp(helpConfig).action(
2691
+ var auth = new Command10("auth").description("enable authentication (email/password + OAuth scaffold)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2433
2692
  (_opts, cmd) => runCommand(
2434
2693
  () => runPattern(
2435
2694
  "enable-auth",
@@ -2455,7 +2714,7 @@ var auth = new Command10("auth").description("enable authentication (email/passw
2455
2714
 
2456
2715
  // src/commands/enable/api.ts
2457
2716
  import { Command as Command11 } from "commander";
2458
- var api = new Command11("api").description("enable the PocketBase REST API").allowUnknownOption(true).configureHelp(helpConfig).action(
2717
+ var api = new Command11("api").description("enable the PocketBase REST API").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2459
2718
  (_opts, cmd) => runCommand(
2460
2719
  () => runPattern(
2461
2720
  "enable-api",
@@ -2481,7 +2740,7 @@ var api = new Command11("api").description("enable the PocketBase REST API").all
2481
2740
 
2482
2741
  // src/commands/enable/api-keys.ts
2483
2742
  import { Command as Command12 } from "commander";
2484
- var apiKeys = new Command12("api-keys").description("enable API key management").allowUnknownOption(true).configureHelp(helpConfig).action(
2743
+ var apiKeys = new Command12("api-keys").description("enable API key management").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2485
2744
  (_opts, cmd) => runCommand(
2486
2745
  () => runPattern(
2487
2746
  "enable-api-keys",
@@ -2507,7 +2766,7 @@ var apiKeys = new Command12("api-keys").description("enable API key management")
2507
2766
 
2508
2767
  // src/commands/enable/backend.ts
2509
2768
  import { Command as Command13 } from "commander";
2510
- var backend = new Command13("backend").description("enable the PocketBase backend").allowUnknownOption(true).configureHelp(helpConfig).action(
2769
+ var backend = new Command13("backend").description("enable the PocketBase backend").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2511
2770
  (_opts, cmd) => runCommand(
2512
2771
  () => runPattern(
2513
2772
  "enable-backend",
@@ -2533,7 +2792,7 @@ var backend = new Command13("backend").description("enable the PocketBase backen
2533
2792
 
2534
2793
  // src/commands/enable/i18n.ts
2535
2794
  import { Command as Command14 } from "commander";
2536
- var i18n = new Command14("i18n").description("enable internationalization").allowUnknownOption(true).configureHelp(helpConfig).action(
2795
+ var i18n = new Command14("i18n").description("enable internationalization").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2537
2796
  (_opts, cmd) => runCommand(
2538
2797
  () => runPattern(
2539
2798
  "enable-i18n",
@@ -2559,7 +2818,7 @@ var i18n = new Command14("i18n").description("enable internationalization").allo
2559
2818
 
2560
2819
  // src/commands/enable/teams.ts
2561
2820
  import { Command as Command15 } from "commander";
2562
- var teams = new Command15("teams").description("enable team / multi-tenant support").allowUnknownOption(true).configureHelp(helpConfig).action(
2821
+ var teams = new Command15("teams").description("enable team / multi-tenant support").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2563
2822
  (_opts, cmd) => runCommand(
2564
2823
  () => runPattern(
2565
2824
  "enable-teams",
@@ -2588,7 +2847,7 @@ import process9 from "node:process";
2588
2847
  import { Command as Command16 } from "commander";
2589
2848
  import * as p14 from "@clack/prompts";
2590
2849
  var PROVIDERS = [{ value: "stripe", label: "Stripe" }];
2591
- var payments = new Command16("payments").description("enable payments").option("--provider <provider>", "payment provider", "stripe").allowUnknownOption(true).configureHelp(helpConfig).action(
2850
+ var payments = new Command16("payments").description("enable payments").option("--provider <provider>", "payment provider", "stripe").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2592
2851
  (opts, cmd) => runCommand(async () => {
2593
2852
  const provider = await resolveProvider(opts.provider, cmd.getOptionValueSource("provider"));
2594
2853
  const input = {
@@ -2675,7 +2934,7 @@ async function ensureKey(envVar, message) {
2675
2934
  async function promptPassword(message) {
2676
2935
  const value = await p14.password({
2677
2936
  message,
2678
- validate: (v9) => v9 && v9.length ? void 0 : "Required"
2937
+ validate: (v10) => v10 && v10.length ? void 0 : "Required"
2679
2938
  });
2680
2939
  if (p14.isCancel(value)) {
2681
2940
  p14.cancel("Operation cancelled.");
@@ -2686,7 +2945,7 @@ async function promptPassword(message) {
2686
2945
 
2687
2946
  // src/commands/enable/subscriptions.ts
2688
2947
  import { Command as Command17 } from "commander";
2689
- var subscriptions = new Command17("subscriptions").description("enable Stripe subscriptions (requires auth and payments)").allowUnknownOption(true).configureHelp(helpConfig).action(
2948
+ var subscriptions = new Command17("subscriptions").description("enable Stripe subscriptions (requires auth and payments)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2690
2949
  (_opts, cmd) => runCommand(
2691
2950
  () => runPattern(
2692
2951
  "enable-subscriptions",
@@ -2712,7 +2971,7 @@ var subscriptions = new Command17("subscriptions").description("enable Stripe su
2712
2971
 
2713
2972
  // src/commands/enable/notifications.ts
2714
2973
  import { Command as Command18 } from "commander";
2715
- var notifications = new Command18("notifications").description("enable in-app notifications with a bell dropdown (requires auth)").allowUnknownOption(true).configureHelp(helpConfig).action(
2974
+ var notifications = new Command18("notifications").description("enable in-app notifications with a bell dropdown (requires auth)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
2716
2975
  (_opts, cmd) => runCommand(
2717
2976
  () => runPattern(
2718
2977
  "enable-notifications",
@@ -2744,13 +3003,13 @@ import pc8 from "picocolors";
2744
3003
 
2745
3004
  // src/lib/server-command.ts
2746
3005
  import process11 from "node:process";
2747
- import * as v5 from "valibot";
3006
+ import * as v6 from "valibot";
2748
3007
  import * as p15 from "@clack/prompts";
2749
3008
  import pc5 from "picocolors";
2750
3009
 
2751
3010
  // src/lib/deploy-config.ts
2752
- import fs18 from "node:fs";
2753
- import path17 from "node:path";
3011
+ import fs19 from "node:fs";
3012
+ import path18 from "node:path";
2754
3013
  import crypto from "node:crypto";
2755
3014
  import { pathToFileURL } from "node:url";
2756
3015
  var CONFIG_BASENAMES = [
@@ -2761,8 +3020,8 @@ var CONFIG_BASENAMES = [
2761
3020
  ];
2762
3021
  function findConfigFile(workspaceRootDir) {
2763
3022
  for (const name of CONFIG_BASENAMES) {
2764
- const file = path17.join(workspaceRootDir, name);
2765
- if (fs18.existsSync(file)) return file;
3023
+ const file = path18.join(workspaceRootDir, name);
3024
+ if (fs19.existsSync(file)) return file;
2766
3025
  }
2767
3026
  return null;
2768
3027
  }
@@ -2770,49 +3029,49 @@ async function loadDeployConfig(workspaceRootDir) {
2770
3029
  const file = findConfigFile(workspaceRootDir);
2771
3030
  if (!file) return {};
2772
3031
  if (file.endsWith(".json")) {
2773
- return JSON.parse(fs18.readFileSync(file, "utf8"));
3032
+ return JSON.parse(fs19.readFileSync(file, "utf8"));
2774
3033
  }
2775
3034
  const url = file.endsWith(".ts") ? await transpileToTemp(file) : pathToFileURL(file).href;
2776
3035
  try {
2777
3036
  const mod = await import(url);
2778
3037
  const config = mod.default;
2779
3038
  if (!config || typeof config !== "object") {
2780
- throw new Error(`${path17.basename(file)} must export a config object as its default export.`);
3039
+ throw new Error(`${path18.basename(file)} must export a config object as its default export.`);
2781
3040
  }
2782
3041
  return config;
2783
3042
  } finally {
2784
- if (url !== pathToFileURL(file).href) fs18.rmSync(new URL(url), { force: true });
3043
+ if (url !== pathToFileURL(file).href) fs19.rmSync(new URL(url), { force: true });
2785
3044
  }
2786
3045
  }
2787
3046
  async function transpileToTemp(file) {
2788
3047
  const { ts } = await import("ts-morph");
2789
- const source = fs18.readFileSync(file, "utf8");
3048
+ const source = fs19.readFileSync(file, "utf8");
2790
3049
  const { outputText } = ts.transpileModule(source, {
2791
3050
  compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 }
2792
3051
  });
2793
- const temp = path17.join(
2794
- path17.dirname(file),
3052
+ const temp = path18.join(
3053
+ path18.dirname(file),
2795
3054
  `.velastack.config.${crypto.randomBytes(4).toString("hex")}.mjs`
2796
3055
  );
2797
- fs18.writeFileSync(temp, outputText);
3056
+ fs19.writeFileSync(temp, outputText);
2798
3057
  return pathToFileURL(temp).href;
2799
3058
  }
2800
3059
  function projectFilePath(workspaceRootDir) {
2801
- return path17.join(workspaceRootDir, ".vela", "project.json");
3060
+ return path18.join(workspaceRootDir, ".vela", "project.json");
2802
3061
  }
2803
3062
  function readProjectFile(workspaceRootDir) {
2804
3063
  const file = projectFilePath(workspaceRootDir);
2805
- if (!fs18.existsSync(file)) return {};
3064
+ if (!fs19.existsSync(file)) return {};
2806
3065
  try {
2807
- return JSON.parse(fs18.readFileSync(file, "utf8"));
3066
+ return JSON.parse(fs19.readFileSync(file, "utf8"));
2808
3067
  } catch {
2809
3068
  return {};
2810
3069
  }
2811
3070
  }
2812
3071
  function writeProjectFile(workspaceRootDir, data) {
2813
3072
  const file = projectFilePath(workspaceRootDir);
2814
- fs18.mkdirSync(path17.dirname(file), { recursive: true });
2815
- fs18.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
3073
+ fs19.mkdirSync(path18.dirname(file), { recursive: true });
3074
+ fs19.writeFileSync(file, JSON.stringify(data, null, 2) + "\n");
2816
3075
  }
2817
3076
  function resolveAppIdentity(workspaceRootDir, config = {}) {
2818
3077
  const project = readProjectFile(workspaceRootDir);
@@ -2837,11 +3096,11 @@ function readAppIdentity(workspaceRootDir, config = {}) {
2837
3096
  }
2838
3097
  function defaultProjectName(workspaceRootDir) {
2839
3098
  try {
2840
- const pkg = readPackageJson(path17.join(workspaceRootDir, "package.json"));
3099
+ const pkg = readPackageJson(path18.join(workspaceRootDir, "package.json"));
2841
3100
  if (typeof pkg.name === "string" && pkg.name.trim()) return pkg.name.trim();
2842
3101
  } catch {
2843
3102
  }
2844
- return path17.basename(workspaceRootDir);
3103
+ return path18.basename(workspaceRootDir);
2845
3104
  }
2846
3105
  function slug(value) {
2847
3106
  return value.toLowerCase().replace(/^@/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 32) || "app";
@@ -2902,15 +3161,15 @@ function releaseId(date = /* @__PURE__ */ new Date()) {
2902
3161
  }
2903
3162
 
2904
3163
  // src/lib/artifact.ts
2905
- import fs20 from "node:fs";
2906
- import path19 from "node:path";
3164
+ import fs21 from "node:fs";
3165
+ import path20 from "node:path";
2907
3166
  import { detect as detect4 } from "package-manager-detector";
2908
3167
  import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
2909
3168
 
2910
3169
  // src/lib/ssh.ts
2911
- import fs19 from "node:fs";
2912
- import os2 from "node:os";
2913
- import path18 from "node:path";
3170
+ import fs20 from "node:fs";
3171
+ import os3 from "node:os";
3172
+ import path19 from "node:path";
2914
3173
  import crypto2 from "node:crypto";
2915
3174
  import process10 from "node:process";
2916
3175
  import { spawn as spawn2 } from "node:child_process";
@@ -2953,9 +3212,9 @@ var SshSession = class {
2953
3212
  }
2954
3213
  async open() {
2955
3214
  if (this.controlPath) return;
2956
- const dir = path18.join(os2.tmpdir(), "vela-ssh");
2957
- fs19.mkdirSync(dir, { recursive: true, mode: 448 });
2958
- const socket = path18.join(dir, `${crypto2.randomBytes(6).toString("hex")}.sock`);
3215
+ const dir = path19.join(os3.tmpdir(), "vela-ssh");
3216
+ fs20.mkdirSync(dir, { recursive: true, mode: 448 });
3217
+ const socket = path19.join(dir, `${crypto2.randomBytes(6).toString("hex")}.sock`);
2959
3218
  this.controlPath = socket;
2960
3219
  const args = [
2961
3220
  ...this.sshArgs(),
@@ -3245,11 +3504,11 @@ function collectArtifact(cwd, config = {}) {
3245
3504
  const outputDir = config.outputDir ?? DEFAULT_OUTPUT_DIR;
3246
3505
  const entries = [];
3247
3506
  const add2 = (rel, remoteDir = "") => {
3248
- const localPath = path19.join(cwd, rel);
3249
- if (fs20.existsSync(localPath)) entries.push({ localPath, remoteDir });
3507
+ const localPath = path20.join(cwd, rel);
3508
+ if (fs21.existsSync(localPath)) entries.push({ localPath, remoteDir });
3250
3509
  };
3251
- const buildPath = path19.join(cwd, outputDir);
3252
- if (!fs20.existsSync(path19.join(buildPath, "index.js"))) {
3510
+ const buildPath = path20.join(cwd, outputDir);
3511
+ if (!fs21.existsSync(path20.join(buildPath, "index.js"))) {
3253
3512
  throw new BuildError(
3254
3513
  `No ${outputDir}/index.js after the build.
3255
3514
 
@@ -3262,8 +3521,8 @@ the adapter in your Vite or Svelte config, then build again.`
3262
3521
  add2("package-lock.json");
3263
3522
  add2(".npmrc");
3264
3523
  add2(MIGRATIONS_DIR);
3265
- const hooks = path19.join(cwd, DATA_DIR, "hooks");
3266
- if (fs20.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
3524
+ const hooks = path20.join(cwd, DATA_DIR, "hooks");
3525
+ if (fs21.existsSync(hooks)) entries.push({ localPath: hooks, remoteDir: "hooks" });
3267
3526
  for (const extra of config.include ?? []) add2(extra);
3268
3527
  return entries;
3269
3528
  }
@@ -3285,11 +3544,11 @@ Name it: \`-t preview:<branch>\`.`
3285
3544
  }
3286
3545
 
3287
3546
  // src/lib/ssh-options.ts
3288
- import * as v4 from "valibot";
3547
+ import * as v5 from "valibot";
3289
3548
  var SSH_OPTION_SCHEMA = {
3290
- identity: v4.optional(v4.string()),
3291
- sshPort: v4.optional(v4.string()),
3292
- acceptHostKeys: v4.optional(v4.boolean())
3549
+ identity: v5.optional(v5.string()),
3550
+ sshPort: v5.optional(v5.string()),
3551
+ acceptHostKeys: v5.optional(v5.boolean())
3293
3552
  };
3294
3553
  function addSshOptions(command) {
3295
3554
  return command.option("-i, --identity <file>", "SSH private key to authenticate with").option("--ssh-port <port>", "SSH port").option("--accept-host-keys", "trust an unknown host key on first connect (CI)");
@@ -3303,7 +3562,7 @@ function sshOptionsFrom(options) {
3303
3562
  }
3304
3563
 
3305
3564
  // src/lib/remote.ts
3306
- import path20 from "node:path";
3565
+ import path21 from "node:path";
3307
3566
  var VELA_ROOT = "/var/lib/vela";
3308
3567
  var VELA_ETC = "/etc/vela";
3309
3568
  var VELA_USER = "vela";
@@ -3311,7 +3570,7 @@ var SCRIPTS_DIR = `${VELA_ROOT}/scripts`;
3311
3570
  var PROVISIONED_MARKER = `${VELA_ETC}/provisioned`;
3312
3571
  var ORIGIN_FILE = `${VELA_ETC}/origin.json`;
3313
3572
  function serverTemplatesDir() {
3314
- return path20.join(templatesDir(), "server");
3573
+ return path21.join(templatesDir(), "server");
3315
3574
  }
3316
3575
  async function syncServerScripts(session) {
3317
3576
  await session.script(`mkdir -p "$1" && chmod 0755 "$1"`, { args: [SCRIPTS_DIR] });
@@ -3394,7 +3653,7 @@ var remotePaths = {
3394
3653
  };
3395
3654
 
3396
3655
  // src/lib/remote-env.ts
3397
- import fs21 from "node:fs";
3656
+ import fs22 from "node:fs";
3398
3657
  import dotenv from "dotenv";
3399
3658
  var KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
3400
3659
  function isValidKey(key) {
@@ -3442,7 +3701,7 @@ function quote(value) {
3442
3701
  return `"${escaped}"`;
3443
3702
  }
3444
3703
  function readLocalEnvFile(file) {
3445
- const parsed = dotenv.parse(fs21.readFileSync(file));
3704
+ const parsed = dotenv.parse(fs22.readFileSync(file));
3446
3705
  const result = {};
3447
3706
  for (const [key, value] of Object.entries(parsed)) {
3448
3707
  if (isValidKey(key)) result[key] = value;
@@ -3554,10 +3813,10 @@ function bold(text18) {
3554
3813
  // src/lib/server-command.ts
3555
3814
  var SERVER_OPTIONS_SCHEMA = {
3556
3815
  ...SSH_OPTION_SCHEMA,
3557
- target: v5.optional(v5.string()),
3558
- server: v5.optional(v5.string())
3816
+ target: v6.optional(v6.string()),
3817
+ server: v6.optional(v6.string())
3559
3818
  };
3560
- var OptionsSchema = v5.object(SERVER_OPTIONS_SCHEMA);
3819
+ var OptionsSchema = v6.object(SERVER_OPTIONS_SCHEMA);
3561
3820
  function addTargetOptions(command, fallback) {
3562
3821
  return addSshOptions(command).option("-t, --target <target>", "which copy of the app to act on", fallback).option("--server <ssh>", "server this target runs on \u2014 recorded on first use");
3563
3822
  }
@@ -3737,17 +3996,17 @@ function envFilePath(workspaceRootDir) {
3737
3996
  import pc7 from "picocolors";
3738
3997
 
3739
3998
  // src/lib/local-env.ts
3740
- import fs22 from "node:fs";
3999
+ import fs23 from "node:fs";
3741
4000
  import * as p16 from "@clack/prompts";
3742
4001
  import pc6 from "picocolors";
3743
4002
  function readLocalEnv(envFile) {
3744
- if (!fs22.existsSync(envFile)) return {};
4003
+ if (!fs23.existsSync(envFile)) return {};
3745
4004
  return readLocalEnvFile(envFile);
3746
4005
  }
3747
4006
  function editLocalEnv(envFile, edit) {
3748
- const before = fs22.existsSync(envFile) ? fs22.readFileSync(envFile, "utf8") : "";
4007
+ const before = fs23.existsSync(envFile) ? fs23.readFileSync(envFile, "utf8") : "";
3749
4008
  const after = edit(before);
3750
- if (after !== before) fs22.writeFileSync(envFile, after);
4009
+ if (after !== before) fs23.writeFileSync(envFile, after);
3751
4010
  }
3752
4011
  function setLocalEnv(envFile, key, value) {
3753
4012
  editLocalEnv(envFile, (content) => upsertEnvVar(content, key, value));
@@ -3879,8 +4138,8 @@ Set ${pc7.cyan("POCKETBASE_SUPERUSER_EMAIL")} and ${pc7.cyan("POCKETBASE_SUPERUS
3879
4138
  }
3880
4139
 
3881
4140
  // src/lib/s3-settings.ts
3882
- import fs23 from "node:fs";
3883
- import path21 from "node:path";
4141
+ import fs24 from "node:fs";
4142
+ import path22 from "node:path";
3884
4143
  var VIRTUAL_HOSTED = [/\.amazonaws\.com$/i, /\.r2\.cloudflarestorage\.com$/i];
3885
4144
  function defaultForcePathStyle(endpoint) {
3886
4145
  let host;
@@ -3918,18 +4177,18 @@ async function hasLocalUploads(session, instance, workspaceRootDir) {
3918
4177
  });
3919
4178
  return result.stdout.trim().length > 0;
3920
4179
  }
3921
- return hasFile(path21.join(workspaceRootDir, DATA_DIR, "storage"));
4180
+ return hasFile(path22.join(workspaceRootDir, DATA_DIR, "storage"));
3922
4181
  }
3923
4182
  function hasFile(dir) {
3924
4183
  let entries;
3925
4184
  try {
3926
- entries = fs23.readdirSync(dir, { withFileTypes: true });
4185
+ entries = fs24.readdirSync(dir, { withFileTypes: true });
3927
4186
  } catch {
3928
4187
  return false;
3929
4188
  }
3930
4189
  for (const entry of entries) {
3931
4190
  if (entry.isFile()) return true;
3932
- if (entry.isDirectory() && hasFile(path21.join(dir, entry.name))) return true;
4191
+ if (entry.isDirectory() && hasFile(path22.join(dir, entry.name))) return true;
3933
4192
  }
3934
4193
  return false;
3935
4194
  }
@@ -4053,14 +4312,14 @@ var smtp = new Command20("smtp").description("configure SMTP for transactional e
4053
4312
  host: () => p18.text({
4054
4313
  message: "SMTP host",
4055
4314
  placeholder: "smtp.example.com",
4056
- validate: (v9) => v9 ? void 0 : "Host is required"
4315
+ validate: (v10) => v10 ? void 0 : "Host is required"
4057
4316
  }),
4058
4317
  port: () => p18.text({
4059
4318
  message: "SMTP port",
4060
4319
  initialValue: "587",
4061
- validate: (v9) => {
4062
- if (!v9) return "Port is required";
4063
- const n = Number(v9);
4320
+ validate: (v10) => {
4321
+ if (!v10) return "Port is required";
4322
+ const n = Number(v10);
4064
4323
  if (!Number.isInteger(n) || n <= 0 || n > 65535) return "Invalid port";
4065
4324
  return void 0;
4066
4325
  }
@@ -4102,43 +4361,41 @@ import process14 from "node:process";
4102
4361
  import { Command as Command21 } from "commander";
4103
4362
  import * as p19 from "@clack/prompts";
4104
4363
  import pc9 from "picocolors";
4105
- var cms = new Command21("cms").description("enable an inline-editing CMS with an admin bar").allowUnknownOption(true).configureHelp(helpConfig).action(
4106
- (_opts, cmd) => runCommand(async () => {
4107
- if (!hasBackend()) {
4364
+ var cms = new Command21("cms").description("enable an inline-editing CMS with an admin bar").option(
4365
+ "--endpoint <url>",
4366
+ "read from a hosted CMS at this URL instead of installing the backend in this app"
4367
+ ).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4368
+ (opts, cmd) => runCommand(async () => {
4369
+ if (!opts.endpoint && !hasBackend()) {
4108
4370
  p19.log.error(
4109
4371
  `${pc9.cyan("vela enable cms")} needs a server to host the CMS backend, and this project is static.
4110
4372
 
4111
- Run ${pc9.cyan("vela bless")} to add a backend first.`
4373
+ Run ${pc9.cyan("vela bless")} to add a backend, or point at a hosted CMS with ${pc9.cyan("vela enable cms --endpoint <url>")}.`
4112
4374
  );
4113
4375
  p19.log.message();
4114
4376
  p19.cancel("Operation failed.");
4115
4377
  process14.exitCode = 1;
4116
4378
  return;
4117
4379
  }
4118
- await runPattern(
4119
- "enable-cms",
4120
- cmd.args,
4121
- {},
4122
- {
4123
- summary: "Enabled CMS.",
4124
- nextSteps: [
4125
- "Run `vela cms editor add you@example.com` to create the first editor login.",
4126
- "Run `vela dev`, open any page with `?edit` on the URL, and sign in from the admin bar.",
4127
- "Wrap page copy in `<CmsText>` and images in `<CmsImage>` to make them editable."
4128
- ],
4129
- task: {
4130
- title: "Enabling CMS",
4131
- success: "Enabled CMS",
4132
- error: "Failed to enable CMS"
4133
- }
4380
+ await runPattern("enable-cms", cmd.args, opts.endpoint ? { endpoint: opts.endpoint } : {}, {
4381
+ summary: "Enabled CMS.",
4382
+ nextSteps: [
4383
+ opts.endpoint ? "Editors are managed where the CMS is hosted, not with `vela cms editor`." : "Run `vela cms editor add you@example.com` to create the first editor login.",
4384
+ "Run `vela dev`, open any page with `?edit` on the URL, and sign in from the admin bar.",
4385
+ "Wrap page copy in `<CmsText>` and images in `<CmsImage>` to make them editable."
4386
+ ],
4387
+ task: {
4388
+ title: "Enabling CMS",
4389
+ success: "Enabled CMS",
4390
+ error: "Failed to enable CMS"
4134
4391
  }
4135
- );
4392
+ });
4136
4393
  }, "Failed to enable CMS.")
4137
4394
  );
4138
4395
 
4139
4396
  // src/commands/enable/blog.ts
4140
4397
  import { Command as Command22 } from "commander";
4141
- var blog = new Command22("blog").description("enable an mdsvex blog with posts, tags, and RSS").allowUnknownOption(true).configureHelp(helpConfig).action(
4398
+ var blog = new Command22("blog").description("enable an mdsvex blog with posts, tags, and RSS").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4142
4399
  (_opts, cmd) => runCommand(
4143
4400
  () => runPattern(
4144
4401
  "enable-blog",
@@ -4164,7 +4421,7 @@ var blog = new Command22("blog").description("enable an mdsvex blog with posts,
4164
4421
 
4165
4422
  // src/commands/enable/content-negotiation.ts
4166
4423
  import { Command as Command23 } from "commander";
4167
- var contentNegotiation = new Command23("content-negotiation").description("enable content negotiation (sveltekit-negotiate)").allowUnknownOption(true).configureHelp(helpConfig).action(
4424
+ var contentNegotiation = new Command23("content-negotiation").description("enable content negotiation (sveltekit-negotiate)").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4168
4425
  (_opts, cmd) => runCommand(
4169
4426
  () => runPattern(
4170
4427
  "enable-content-negotiation",
@@ -4214,7 +4471,7 @@ async function runDisable(opts, flags, cmdArgs) {
4214
4471
  }
4215
4472
 
4216
4473
  // src/commands/disable/auth.ts
4217
- var auth2 = new Command25("auth").description("disable authentication").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4474
+ var auth2 = new Command25("auth").description("disable authentication").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4218
4475
  (opts, cmd) => runCommand(
4219
4476
  () => runDisable(
4220
4477
  {
@@ -4241,7 +4498,7 @@ var auth2 = new Command25("auth").description("disable authentication").option("
4241
4498
 
4242
4499
  // src/commands/disable/api.ts
4243
4500
  import { Command as Command26 } from "commander";
4244
- var api2 = new Command26("api").description("disable the REST API").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4501
+ var api2 = new Command26("api").description("disable the REST API").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4245
4502
  (opts, cmd) => runCommand(
4246
4503
  () => runDisable(
4247
4504
  {
@@ -4265,7 +4522,7 @@ var api2 = new Command26("api").description("disable the REST API").option("-y,
4265
4522
 
4266
4523
  // src/commands/disable/api-keys.ts
4267
4524
  import { Command as Command27 } from "commander";
4268
- var apiKeys2 = new Command27("api-keys").description("disable API key management").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4525
+ var apiKeys2 = new Command27("api-keys").description("disable API key management").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4269
4526
  (opts, cmd) => runCommand(
4270
4527
  () => runDisable(
4271
4528
  {
@@ -4289,7 +4546,7 @@ var apiKeys2 = new Command27("api-keys").description("disable API key management
4289
4546
 
4290
4547
  // src/commands/disable/backend.ts
4291
4548
  import { Command as Command28 } from "commander";
4292
- var backend2 = new Command28("backend").description("disable the PocketBase backend").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4549
+ var backend2 = new Command28("backend").description("disable the PocketBase backend").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4293
4550
  (opts, cmd) => runCommand(
4294
4551
  () => runDisable(
4295
4552
  {
@@ -4313,7 +4570,7 @@ var backend2 = new Command28("backend").description("disable the PocketBase back
4313
4570
 
4314
4571
  // src/commands/disable/content-negotiation.ts
4315
4572
  import { Command as Command29 } from "commander";
4316
- var contentNegotiation2 = new Command29("content-negotiation").description("disable content negotiation").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4573
+ var contentNegotiation2 = new Command29("content-negotiation").description("disable content negotiation").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4317
4574
  (opts, cmd) => runCommand(
4318
4575
  () => runDisable(
4319
4576
  {
@@ -4337,7 +4594,7 @@ var contentNegotiation2 = new Command29("content-negotiation").description("disa
4337
4594
 
4338
4595
  // src/commands/disable/i18n.ts
4339
4596
  import { Command as Command30 } from "commander";
4340
- var i18n2 = new Command30("i18n").description("disable internationalization").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4597
+ var i18n2 = new Command30("i18n").description("disable internationalization").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4341
4598
  (opts, cmd) => runCommand(
4342
4599
  () => runDisable(
4343
4600
  {
@@ -4364,7 +4621,7 @@ var i18n2 = new Command30("i18n").description("disable internationalization").op
4364
4621
 
4365
4622
  // src/commands/disable/teams.ts
4366
4623
  import { Command as Command31 } from "commander";
4367
- var teams2 = new Command31("teams").description("disable teams").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4624
+ var teams2 = new Command31("teams").description("disable teams").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4368
4625
  (opts, cmd) => runCommand(
4369
4626
  () => runDisable(
4370
4627
  {
@@ -4391,7 +4648,7 @@ var teams2 = new Command31("teams").description("disable teams").option("-y, --y
4391
4648
 
4392
4649
  // src/commands/disable/payments.ts
4393
4650
  import { Command as Command32 } from "commander";
4394
- var payments2 = new Command32("payments").description("disable payments").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4651
+ var payments2 = new Command32("payments").description("disable payments").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4395
4652
  (opts, cmd) => runCommand(
4396
4653
  () => runDisable(
4397
4654
  {
@@ -4495,7 +4752,7 @@ async function runDestroy(slug2, model, confirmMessage, report4, flags) {
4495
4752
  var form2 = new Command36("form").description("destroy a form generated by `vela generate form`").argument("<model>", "model name used when the form was generated (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").option(
4496
4753
  "--route <route>",
4497
4754
  "custom route the form was generated at (must match the --route used at generation)"
4498
- ).allowUnknownOption(true).configureHelp(helpConfig).action(
4755
+ ).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4499
4756
  (model, opts) => runCommand(
4500
4757
  () => runDestroy(
4501
4758
  "destroy-form",
@@ -4517,7 +4774,7 @@ var form2 = new Command36("form").description("destroy a form generated by `vela
4517
4774
 
4518
4775
  // src/commands/destroy/schema.ts
4519
4776
  import { Command as Command37 } from "commander";
4520
- var schema2 = new Command37("schema").description("destroy a zod schema generated by `vela generate schema`").argument("<model>", "schema model name (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4777
+ var schema2 = new Command37("schema").description("destroy a zod schema generated by `vela generate schema`").argument("<model>", "schema model name (e.g., contact, login)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4521
4778
  (model, opts) => runCommand(
4522
4779
  () => runDestroy(
4523
4780
  "destroy-schema",
@@ -4539,7 +4796,7 @@ var schema2 = new Command37("schema").description("destroy a zod schema generate
4539
4796
 
4540
4797
  // src/commands/destroy/resource.ts
4541
4798
  import { Command as Command38 } from "commander";
4542
- var resource2 = new Command38("resource").description("destroy a resource generated by `vela generate resource`").argument("<model>", "model path used when the resource was generated (e.g., contacts, articles)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).configureHelp(helpConfig).action(
4799
+ var resource2 = new Command38("resource").description("destroy a resource generated by `vela generate resource`").argument("<model>", "model path used when the resource was generated (e.g., contacts, articles)").option("-y, --yes", "skip confirmation prompt").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4543
4800
  (model, opts) => runCommand(
4544
4801
  () => runDestroy(
4545
4802
  "destroy-resource",
@@ -4564,7 +4821,7 @@ import { Command as Command39 } from "commander";
4564
4821
  var scaffold2 = new Command39("scaffold").description("destroy a scaffold generated by `vela generate scaffold`").argument("<model>", "model name used when the scaffold was generated (e.g., contact, todo)").option("-y, --yes", "skip confirmation prompt").option(
4565
4822
  "--route <route>",
4566
4823
  "custom route the scaffold was generated at (must match the --route used at generation)"
4567
- ).allowUnknownOption(true).configureHelp(helpConfig).action(
4824
+ ).allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(
4568
4825
  (model, opts) => runCommand(
4569
4826
  () => runDestroy(
4570
4827
  "destroy-scaffold",
@@ -5119,8 +5376,8 @@ var ui = new Command47("ui").description("generate ui components").configureHelp
5119
5376
  import { Command as Command50 } from "commander";
5120
5377
 
5121
5378
  // src/commands/legal/terms.ts
5122
- import fs24 from "node:fs";
5123
- import path22 from "node:path";
5379
+ import fs25 from "node:fs";
5380
+ import path23 from "node:path";
5124
5381
  import { Command as Command48 } from "commander";
5125
5382
  import * as p32 from "@clack/prompts";
5126
5383
 
@@ -5779,22 +6036,22 @@ async function termsAction() {
5779
6036
  mobileApp,
5780
6037
  contact
5781
6038
  });
5782
- const termsPage = path22.join(
6039
+ const termsPage = path23.join(
5783
6040
  workspaceRootDir,
5784
6041
  publicRoutesDir,
5785
6042
  LEGAL_DIR,
5786
6043
  "terms",
5787
6044
  "+page.svelte"
5788
6045
  );
5789
- const termsPageTs = path22.join(workspaceRootDir, publicRoutesDir, LEGAL_DIR, "terms", "+page.ts");
5790
- fs24.mkdirSync(path22.dirname(termsPage), { recursive: true });
5791
- fs24.writeFileSync(termsPage, html);
5792
- fs24.writeFileSync(
6046
+ const termsPageTs = path23.join(workspaceRootDir, publicRoutesDir, LEGAL_DIR, "terms", "+page.ts");
6047
+ fs25.mkdirSync(path23.dirname(termsPage), { recursive: true });
6048
+ fs25.writeFileSync(termsPage, html);
6049
+ fs25.writeFileSync(
5793
6050
  termsPageTs,
5794
6051
  pageMetaTagsLoader("Terms of Service", `Terms of Service for ${core.websiteName}`)
5795
6052
  );
5796
- const relativeTermsPage = path22.relative(workspaceRootDir, termsPage);
5797
- const relativeTermsPageTs = path22.relative(workspaceRootDir, termsPageTs);
6053
+ const relativeTermsPage = path23.relative(workspaceRootDir, termsPage);
6054
+ const relativeTermsPageTs = path23.relative(workspaceRootDir, termsPageTs);
5798
6055
  reportResult({
5799
6056
  summary: "Generated placeholder terms and conditions.",
5800
6057
  filesCreated: [relativeTermsPage, relativeTermsPageTs],
@@ -5808,8 +6065,8 @@ async function termsAction() {
5808
6065
  var terms = new Command48("terms").description("generate placeholder terms and conditions").configureHelp(helpConfig).action(() => runCommand(termsAction, "Failed to generate terms and conditions."));
5809
6066
 
5810
6067
  // src/commands/legal/privacy.ts
5811
- import fs25 from "node:fs";
5812
- import path23 from "node:path";
6068
+ import fs26 from "node:fs";
6069
+ import path24 from "node:path";
5813
6070
  import { Command as Command49 } from "commander";
5814
6071
  import * as p33 from "@clack/prompts";
5815
6072
  var mapLabels = {
@@ -5898,9 +6155,9 @@ var compute2 = (a) => {
5898
6155
  });
5899
6156
  const piSelections = a.personalInfo ?? [];
5900
6157
  const piLabels = piSelections.map(
5901
- (v9) => mapLabels.personalInfo[v9] ?? v9
6158
+ (v10) => mapLabels.personalInfo[v10] ?? v10
5902
6159
  );
5903
- const lookup = (map, vs) => (vs ?? []).map((v9) => map[v9] ?? v9);
6160
+ const lookup = (map, vs) => (vs ?? []).map((v10) => map[v10] ?? v10);
5904
6161
  const companyName = a.core?.entityType === "business" ? a.core?.businessName ?? a.core?.websiteName : a.core?.websiteName ?? "Our Company";
5905
6162
  const companyAddress = a.core?.entityType === "business" ? a.core?.businessAddress ?? "" : "";
5906
6163
  const websiteName = a.core?.websiteName ?? "our website";
@@ -6522,28 +6779,28 @@ async function privacyAction() {
6522
6779
  kids,
6523
6780
  retention
6524
6781
  });
6525
- const privacyPage = path23.join(
6782
+ const privacyPage = path24.join(
6526
6783
  workspaceRootDir,
6527
6784
  publicRoutesDir,
6528
6785
  LEGAL_DIR,
6529
6786
  "privacy",
6530
6787
  "+page.svelte"
6531
6788
  );
6532
- const privacyPageTs = path23.join(
6789
+ const privacyPageTs = path24.join(
6533
6790
  workspaceRootDir,
6534
6791
  publicRoutesDir,
6535
6792
  LEGAL_DIR,
6536
6793
  "privacy",
6537
6794
  "+page.ts"
6538
6795
  );
6539
- fs25.mkdirSync(path23.dirname(privacyPage), { recursive: true });
6540
- fs25.writeFileSync(privacyPage, html);
6541
- fs25.writeFileSync(
6796
+ fs26.mkdirSync(path24.dirname(privacyPage), { recursive: true });
6797
+ fs26.writeFileSync(privacyPage, html);
6798
+ fs26.writeFileSync(
6542
6799
  privacyPageTs,
6543
6800
  pageMetaTagsLoader("Privacy Policy", `Privacy Policy for ${core.websiteName}`)
6544
6801
  );
6545
- const relativePrivacyPage = path23.relative(workspaceRootDir, privacyPage);
6546
- const relativePrivacyPageTs = path23.relative(workspaceRootDir, privacyPageTs);
6802
+ const relativePrivacyPage = path24.relative(workspaceRootDir, privacyPage);
6803
+ const relativePrivacyPageTs = path24.relative(workspaceRootDir, privacyPageTs);
6547
6804
  reportResult({
6548
6805
  summary: "Generated placeholder privacy policy.",
6549
6806
  filesCreated: [relativePrivacyPage, relativePrivacyPageTs],
@@ -6566,8 +6823,8 @@ import { Command as Command56 } from "commander";
6566
6823
  import { Command as Command51 } from "commander";
6567
6824
 
6568
6825
  // src/lib/data.ts
6569
- import fs26 from "node:fs";
6570
- import path24 from "node:path";
6826
+ import fs27 from "node:fs";
6827
+ import path25 from "node:path";
6571
6828
  import { ClientResponseError } from "pocketbase";
6572
6829
 
6573
6830
  // src/lib/collections.ts
@@ -6604,14 +6861,14 @@ function dependencyOrder(collections2, startingCollectionId) {
6604
6861
 
6605
6862
  // src/lib/data.ts
6606
6863
  function dataDir(cwd, kind) {
6607
- return path24.join(cwd, DATA_DIR, kind);
6864
+ return path25.join(cwd, DATA_DIR, kind);
6608
6865
  }
6609
6866
  function getDataFiles(cwd, kind) {
6610
6867
  const dir = dataDir(cwd, kind);
6611
- if (!fs26.existsSync(dir)) return [];
6612
- return fs26.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
6868
+ if (!fs27.existsSync(dir)) return [];
6869
+ return fs27.readdirSync(dir).filter((file) => file.endsWith(".json")).sort((a, b) => a.localeCompare(b)).map((file) => ({
6613
6870
  collectionName: file.replace(/\.json$/i, "").replace(/^\d+[-_]?/, ""),
6614
- filePath: path24.join(dir, file)
6871
+ filePath: path25.join(dir, file)
6615
6872
  }));
6616
6873
  }
6617
6874
  function getSeedFiles(cwd) {
@@ -6621,7 +6878,7 @@ function getFixtureFiles(cwd) {
6621
6878
  return getDataFiles(cwd, "fixtures");
6622
6879
  }
6623
6880
  function readRecords(filePath) {
6624
- return JSON.parse(fs26.readFileSync(filePath, "utf8"));
6881
+ return JSON.parse(fs27.readFileSync(filePath, "utf8"));
6625
6882
  }
6626
6883
  function readSeedIds(cwd) {
6627
6884
  const ids = /* @__PURE__ */ new Map();
@@ -6658,7 +6915,7 @@ function describeError(e) {
6658
6915
  return e instanceof Error ? e.message : String(e);
6659
6916
  }
6660
6917
  function label3(cwd, filePath, count) {
6661
- return `${path24.relative(cwd, filePath)} (${count} records)`;
6918
+ return `${path25.relative(cwd, filePath)} (${count} records)`;
6662
6919
  }
6663
6920
  async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
6664
6921
  const records = readRecords(filePath);
@@ -6666,7 +6923,7 @@ async function createRecords(pb, kind, cwd, { collectionName, filePath }) {
6666
6923
  try {
6667
6924
  await pb.collection(collectionName).create(record);
6668
6925
  } catch (e) {
6669
- throw new DataLoadError(kind, path24.relative(cwd, filePath), index, e);
6926
+ throw new DataLoadError(kind, path25.relative(cwd, filePath), index, e);
6670
6927
  }
6671
6928
  }
6672
6929
  return records.length;
@@ -6840,8 +7097,8 @@ var reset = new Command53("reset").description("clear and reload fixtures").conf
6840
7097
  );
6841
7098
 
6842
7099
  // src/commands/fixtures/generate.ts
6843
- import fs27 from "node:fs";
6844
- import path25 from "node:path";
7100
+ import fs28 from "node:fs";
7101
+ import path26 from "node:path";
6845
7102
  import { Command as Command54, InvalidArgumentError } from "commander";
6846
7103
  import * as p34 from "@clack/prompts";
6847
7104
  import { annotate } from "annotate-json-schema";
@@ -6878,9 +7135,9 @@ async function loadCollections(pb) {
6878
7135
  }
6879
7136
  async function generateFixtureFiles(pb, workspaceRootDir, opts) {
6880
7137
  const fixturesDir = dataDir(workspaceRootDir, "fixtures");
6881
- fs27.mkdirSync(fixturesDir, { recursive: true });
6882
- for (const file of fs27.readdirSync(fixturesDir)) {
6883
- if (file.endsWith(".json")) fs27.unlinkSync(path25.join(fixturesDir, file));
7138
+ fs28.mkdirSync(fixturesDir, { recursive: true });
7139
+ for (const file of fs28.readdirSync(fixturesDir)) {
7140
+ if (file.endsWith(".json")) fs28.unlinkSync(path26.join(fixturesDir, file));
6884
7141
  }
6885
7142
  if (opts.seed !== void 0) faker.seed(opts.seed);
6886
7143
  const generator = createGenerator({
@@ -6947,8 +7204,8 @@ async function generateFixtureFiles(pb, workspaceRootDir, opts) {
6947
7204
  items.push(record);
6948
7205
  }
6949
7206
  const filename = `${padZeros(fileIndex, 2)}-${collection.name}.json`;
6950
- fs27.writeFileSync(path25.join(fixturesDir, filename), JSON.stringify(items, null, 2));
6951
- writtenFiles.push(`${path25.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
7207
+ fs28.writeFileSync(path26.join(fixturesDir, filename), JSON.stringify(items, null, 2));
7208
+ writtenFiles.push(`${path26.join(DATA_DIR, "fixtures", filename)} (${items.length} records)`);
6952
7209
  fileIndex++;
6953
7210
  }
6954
7211
  return { writtenFiles, warnings };
@@ -7095,8 +7352,8 @@ var load2 = new Command57("load").description("load seeds into the database").op
7095
7352
  );
7096
7353
 
7097
7354
  // src/commands/seeds/save.ts
7098
- import fs28 from "node:fs";
7099
- import path26 from "node:path";
7355
+ import fs29 from "node:fs";
7356
+ import path27 from "node:path";
7100
7357
  import { Command as Command58 } from "commander";
7101
7358
  var padZeros2 = (num, length) => num.toString().padStart(length, "0");
7102
7359
  function filterSystemFields(record, systemFieldNames) {
@@ -7116,10 +7373,10 @@ var save = new Command58("save").description("save the current data as seeds").o
7116
7373
  if (existing.length > 0 && !opts.force) {
7117
7374
  throw new Error("Existing seed files found in data/seeds. Pass --force to overwrite.");
7118
7375
  }
7119
- fs28.mkdirSync(seedsPath, { recursive: true });
7376
+ fs29.mkdirSync(seedsPath, { recursive: true });
7120
7377
  if (opts.force) {
7121
- for (const file of fs28.readdirSync(seedsPath)) {
7122
- if (file.endsWith(".json")) fs28.unlinkSync(path26.join(seedsPath, file));
7378
+ for (const file of fs29.readdirSync(seedsPath)) {
7379
+ if (file.endsWith(".json")) fs29.unlinkSync(path27.join(seedsPath, file));
7123
7380
  }
7124
7381
  }
7125
7382
  const saved = [];
@@ -7148,13 +7405,13 @@ var save = new Command58("save").description("save the current data as seeds").o
7148
7405
  const filtered = records.map(
7149
7406
  (r) => filterSystemFields(r, systemFieldNames)
7150
7407
  );
7151
- const relativeSeedPath = path26.join(
7408
+ const relativeSeedPath = path27.join(
7152
7409
  DATA_DIR,
7153
7410
  "seeds",
7154
7411
  `${padZeros2(count, 2)}-${collectionName}.json`
7155
7412
  );
7156
- const seedPath = path26.join(workspaceRootDir, relativeSeedPath);
7157
- fs28.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
7413
+ const seedPath = path27.join(workspaceRootDir, relativeSeedPath);
7414
+ fs29.writeFileSync(seedPath, JSON.stringify(filtered, null, 2));
7158
7415
  saved.push(`${relativeSeedPath} (${filtered.length} records)`);
7159
7416
  count++;
7160
7417
  }
@@ -7220,7 +7477,7 @@ import * as p37 from "@clack/prompts";
7220
7477
  import makeFetchCookie2 from "fetch-cookie";
7221
7478
 
7222
7479
  // src/commands/login.ts
7223
- import os3 from "node:os";
7480
+ import os4 from "node:os";
7224
7481
  import { Command as Command61 } from "commander";
7225
7482
  import * as p36 from "@clack/prompts";
7226
7483
  import makeFetchCookie from "fetch-cookie";
@@ -7254,7 +7511,7 @@ var login = new Command61("login").description("login to velastack.dev").configu
7254
7511
  }, "Failed to login.")
7255
7512
  );
7256
7513
  async function issueApiKey(fetchCookie) {
7257
- const label4 = `CLI - ${os3.hostname()}`;
7514
+ const label4 = `CLI - ${os4.hostname()}`;
7258
7515
  await fetchCookie(`${API_URL}/api-keys/new`, {
7259
7516
  method: "POST",
7260
7517
  headers: {
@@ -7365,7 +7622,7 @@ import { Command as Command70 } from "commander";
7365
7622
  import { Command as Command65 } from "commander";
7366
7623
 
7367
7624
  // src/lib/migrate.ts
7368
- import path27 from "node:path";
7625
+ import path28 from "node:path";
7369
7626
  import process19 from "node:process";
7370
7627
  import { x as x2 } from "tinyexec";
7371
7628
  async function runPocketbaseMigrate(args) {
@@ -7376,9 +7633,9 @@ async function runPocketbaseMigrate(args) {
7376
7633
  binaryPath,
7377
7634
  [
7378
7635
  "--dir",
7379
- path27.join(cwd, DATA_DIR),
7636
+ path28.join(cwd, DATA_DIR),
7380
7637
  "--migrationsDir",
7381
- path27.join(cwd, MIGRATIONS_DIR),
7638
+ path28.join(cwd, MIGRATIONS_DIR),
7382
7639
  "migrate",
7383
7640
  ...args
7384
7641
  ],
@@ -7426,8 +7683,8 @@ var down = new Command66("down").alias("rollback").description("revert the last
7426
7683
  );
7427
7684
 
7428
7685
  // src/commands/migrate/create.ts
7429
- import fs29 from "node:fs";
7430
- import path28 from "node:path";
7686
+ import fs30 from "node:fs";
7687
+ import path29 from "node:path";
7431
7688
  import process20 from "node:process";
7432
7689
  import { Command as Command67 } from "commander";
7433
7690
  var create2 = new Command67("create").alias("new").description("create a new blank migration").argument("<name>", "migration name (snake_case)").configureHelp(helpConfig).action(
@@ -7439,7 +7696,7 @@ var create2 = new Command67("create").alias("new").description("create a new bla
7439
7696
  const added = [...after].filter((f) => !before.has(f));
7440
7697
  reportResult({
7441
7698
  summary: `Created blank migration ${name}.`,
7442
- filesCreated: added.map((f) => path28.join(MIGRATIONS_DIR, f)),
7699
+ filesCreated: added.map((f) => path29.join(MIGRATIONS_DIR, f)),
7443
7700
  nextSteps: [
7444
7701
  `Open the new file in ${MIGRATIONS_DIR}/ and fill in the up/down handlers.`,
7445
7702
  "Run `vela migrate up` to apply the migration once the handlers are written."
@@ -7448,14 +7705,14 @@ var create2 = new Command67("create").alias("new").description("create a new bla
7448
7705
  }, "Failed to create migration.")
7449
7706
  );
7450
7707
  function listMigrationFiles(cwd) {
7451
- const dir = path28.join(cwd, MIGRATIONS_DIR);
7452
- if (!fs29.existsSync(dir)) return /* @__PURE__ */ new Set();
7453
- return new Set(fs29.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
7708
+ const dir = path29.join(cwd, MIGRATIONS_DIR);
7709
+ if (!fs30.existsSync(dir)) return /* @__PURE__ */ new Set();
7710
+ return new Set(fs30.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
7454
7711
  }
7455
7712
 
7456
7713
  // src/commands/migrate/collections.ts
7457
- import fs30 from "node:fs";
7458
- import path29 from "node:path";
7714
+ import fs31 from "node:fs";
7715
+ import path30 from "node:path";
7459
7716
  import process21 from "node:process";
7460
7717
  import { Command as Command68 } from "commander";
7461
7718
  var collections = new Command68("collections").alias("snapshot").description("snapshot local collections into a new migration").configureHelp(helpConfig).action(
@@ -7473,7 +7730,7 @@ var collections = new Command68("collections").alias("snapshot").description("sn
7473
7730
  }
7474
7731
  reportResult({
7475
7732
  summary: "Snapshotted local collections into a new migration.",
7476
- filesCreated: added.map((f) => path29.join(MIGRATIONS_DIR, f)),
7733
+ filesCreated: added.map((f) => path30.join(MIGRATIONS_DIR, f)),
7477
7734
  nextSteps: [
7478
7735
  `Review the generated snapshot in ${MIGRATIONS_DIR}/.`,
7479
7736
  "Commit the snapshot so teammates pick up the new schema.",
@@ -7483,9 +7740,9 @@ var collections = new Command68("collections").alias("snapshot").description("sn
7483
7740
  }, "Failed to snapshot collections.")
7484
7741
  );
7485
7742
  function listMigrationFiles2(cwd) {
7486
- const dir = path29.join(cwd, MIGRATIONS_DIR);
7487
- if (!fs30.existsSync(dir)) return /* @__PURE__ */ new Set();
7488
- return new Set(fs30.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
7743
+ const dir = path30.join(cwd, MIGRATIONS_DIR);
7744
+ if (!fs31.existsSync(dir)) return /* @__PURE__ */ new Set();
7745
+ return new Set(fs31.readdirSync(dir).filter((f) => /\.[jt]s$/.test(f)));
7489
7746
  }
7490
7747
 
7491
7748
  // src/commands/migrate/history-sync.ts
@@ -7504,8 +7761,8 @@ var historySync = new Command69("history-sync").description("drop _migrations ro
7504
7761
  var migrate = new Command70("migrate").description("manage database migrations").configureHelp(helpConfig).action(() => runCommand(runMigrateUp, "Failed to run migrations.")).addCommand(up).addCommand(down).addCommand(create2).addCommand(collections).addCommand(historySync);
7505
7762
 
7506
7763
  // src/commands/dev.ts
7507
- import fs31 from "node:fs";
7508
- import path31 from "node:path";
7764
+ import fs32 from "node:fs";
7765
+ import path32 from "node:path";
7509
7766
  import process23 from "node:process";
7510
7767
  import { performance } from "node:perf_hooks";
7511
7768
  import { Command as Command71, InvalidArgumentError as InvalidArgumentError4 } from "commander";
@@ -7513,7 +7770,7 @@ import pc15 from "picocolors";
7513
7770
  import PocketBase4 from "pocketbase";
7514
7771
 
7515
7772
  // src/lib/vite.ts
7516
- import path30 from "node:path";
7773
+ import path31 from "node:path";
7517
7774
  import process22 from "node:process";
7518
7775
  import { createRequire as createRequire2 } from "node:module";
7519
7776
  import { pathToFileURL as pathToFileURL2 } from "node:url";
@@ -7533,7 +7790,7 @@ function viteVersionError(version) {
7533
7790
  }
7534
7791
  function resolveProjectVite(cwd) {
7535
7792
  try {
7536
- return createRequire2(path30.join(cwd, "package.json")).resolve("vite");
7793
+ return createRequire2(path31.join(cwd, "package.json")).resolve("vite");
7537
7794
  } catch {
7538
7795
  return null;
7539
7796
  }
@@ -7562,21 +7819,21 @@ var dev = new Command71("dev").description("start the development server").optio
7562
7819
  process23.env.VELA_DATA_DIR ??= localDataDir(cwd);
7563
7820
  const startTime = performance.now();
7564
7821
  const { createServer, version } = await loadVite(cwd);
7565
- const viteMetadataDir = path31.join(cwd, "node_modules", ".vite");
7566
- const viteMetadataFile = path31.join(viteMetadataDir, "_pocketbase_metadata.json");
7822
+ const viteMetadataDir = path32.join(cwd, "node_modules", ".vite");
7823
+ const viteMetadataFile = path32.join(viteMetadataDir, "_pocketbase_metadata.json");
7567
7824
  let pbProc;
7568
7825
  const backend3 = hasBackend(cwd);
7569
7826
  const needsStart = backend3 && !process23.env.POCKETBASE_URL;
7570
7827
  const cleanup = () => {
7571
7828
  if (pbProc?.pid) pbProc.kill();
7572
- if (fs31.existsSync(viteMetadataFile)) fs31.rmSync(viteMetadataFile);
7829
+ if (fs32.existsSync(viteMetadataFile)) fs32.rmSync(viteMetadataFile);
7573
7830
  };
7574
7831
  if (needsStart) {
7575
- const dataDir2 = path31.join(cwd, DATA_DIR);
7832
+ const dataDir2 = path32.join(cwd, DATA_DIR);
7576
7833
  const started = await startPocketbaseServe({
7577
7834
  dataDir: dataDir2,
7578
7835
  migrationsDir: MIGRATIONS_DIR,
7579
- hooksDir: path31.join(dataDir2, "hooks"),
7836
+ hooksDir: path32.join(dataDir2, "hooks"),
7580
7837
  dev: true,
7581
7838
  stdio: "pipe"
7582
7839
  });
@@ -7607,8 +7864,8 @@ var dev = new Command71("dev").description("start the development server").optio
7607
7864
  if (!backend3) return;
7608
7865
  const { address, port: vitePort } = server.httpServer.address();
7609
7866
  const viteHost = address === "::1" ? "localhost" : address;
7610
- await fs31.promises.mkdir(viteMetadataDir, { recursive: true });
7611
- await fs31.promises.writeFile(
7867
+ await fs32.promises.mkdir(viteMetadataDir, { recursive: true });
7868
+ await fs32.promises.writeFile(
7612
7869
  viteMetadataFile,
7613
7870
  JSON.stringify({
7614
7871
  pocketbaseUrl: process23.env.POCKETBASE_URL,
@@ -7640,18 +7897,18 @@ var dev = new Command71("dev").description("start the development server").optio
7640
7897
  });
7641
7898
  async function startWatchingTypes(cwd, pb) {
7642
7899
  const { processTypes } = await import("@velastack/pocketbase-codegen");
7643
- const typesDir = path31.resolve(cwd, ".svelte-kit", "types");
7644
- const pocketbaseDir = path31.join(typesDir, "pocketbase");
7645
- const pocketbaseTypes = path31.join(pocketbaseDir, "$types.d.ts");
7900
+ const typesDir = path32.resolve(cwd, ".svelte-kit", "types");
7901
+ const pocketbaseDir = path32.join(typesDir, "pocketbase");
7902
+ const pocketbaseTypes = path32.join(pocketbaseDir, "$types.d.ts");
7646
7903
  const regenerate = () => processTypes(pb, typesDir).catch(() => {
7647
7904
  });
7648
7905
  await regenerate();
7649
7906
  void (async () => {
7650
7907
  for (; ; ) {
7651
7908
  try {
7652
- await fs31.promises.mkdir(pocketbaseDir, { recursive: true });
7653
- for await (const event of fs31.promises.watch(pocketbaseDir)) {
7654
- if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs31.existsSync(pocketbaseTypes)) {
7909
+ await fs32.promises.mkdir(pocketbaseDir, { recursive: true });
7910
+ for await (const event of fs32.promises.watch(pocketbaseDir)) {
7911
+ if (event.eventType === "rename" && event.filename === "$types.d.ts" && !fs32.existsSync(pocketbaseTypes)) {
7655
7912
  setTimeout(regenerate, 100);
7656
7913
  }
7657
7914
  }
@@ -7663,8 +7920,8 @@ async function startWatchingTypes(cwd, pb) {
7663
7920
  }
7664
7921
 
7665
7922
  // src/commands/build.ts
7666
- import fs32 from "node:fs";
7667
- import path32 from "node:path";
7923
+ import fs33 from "node:fs";
7924
+ import path33 from "node:path";
7668
7925
  import process25 from "node:process";
7669
7926
  import { Command as Command72 } from "commander";
7670
7927
  import * as p40 from "@clack/prompts";
@@ -7702,7 +7959,7 @@ function splitHosts(value) {
7702
7959
  }
7703
7960
 
7704
7961
  // src/commands/build.ts
7705
- var PRERENDERED_DIR = path32.join(".svelte-kit", "output", "prerendered");
7962
+ var PRERENDERED_DIR = path33.join(".svelte-kit", "output", "prerendered");
7706
7963
  var build = new Command72("build").description("build the app").configureHelp(helpConfig).option("-t, --target <target>", "which copy of the app to build for", PRODUCTION_TARGET).action(async (options) => {
7707
7964
  const cwd = process25.cwd();
7708
7965
  applyBuildEnv(cwd);
@@ -7715,11 +7972,11 @@ var build = new Command72("build").description("build the app").configureHelp(he
7715
7972
  };
7716
7973
  if (needsStart) {
7717
7974
  await ensureSuperuser(cwd);
7718
- const dataDir2 = path32.join(cwd, DATA_DIR);
7975
+ const dataDir2 = path33.join(cwd, DATA_DIR);
7719
7976
  const started = await startPocketbaseServe({
7720
7977
  dataDir: dataDir2,
7721
7978
  migrationsDir: MIGRATIONS_DIR,
7722
- hooksDir: path32.join(dataDir2, "hooks"),
7979
+ hooksDir: path33.join(dataDir2, "hooks"),
7723
7980
  dev: true
7724
7981
  });
7725
7982
  pbProc = started.proc;
@@ -7758,8 +8015,8 @@ async function originForBuild(cwd, target) {
7758
8015
  }
7759
8016
  }
7760
8017
  function warnIfPrerendered(cwd) {
7761
- const dir = path32.join(cwd, PRERENDERED_DIR);
7762
- if (!fs32.existsSync(dir) || fs32.readdirSync(dir).length === 0) return;
8018
+ const dir = path33.join(cwd, PRERENDERED_DIR);
8019
+ if (!fs33.existsSync(dir) || fs33.readdirSync(dir).length === 0) return;
7763
8020
  p40.log.warn(
7764
8021
  `Prerendered pages were built with no domain configured, so their canonical
7765
8022
  links point at SvelteKit's placeholder host rather than at this site.
@@ -7769,7 +8026,7 @@ Set one with ${pc16.cyan("vela deploy --domain example.com")}, or pass ${pc16.cy
7769
8026
  }
7770
8027
 
7771
8028
  // src/commands/preview.ts
7772
- import path33 from "node:path";
8029
+ import path34 from "node:path";
7773
8030
  import process26 from "node:process";
7774
8031
  import { Command as Command73 } from "commander";
7775
8032
  import { x as x4 } from "tinyexec";
@@ -7784,11 +8041,11 @@ var preview = new Command73("preview").description("preview the built app").conf
7784
8041
  if (pbProc?.pid) pbProc.kill();
7785
8042
  };
7786
8043
  if (needsStart) {
7787
- const dataDir2 = path33.join(cwd, DATA_DIR);
8044
+ const dataDir2 = path34.join(cwd, DATA_DIR);
7788
8045
  const started = await startPocketbaseServe({
7789
8046
  dataDir: dataDir2,
7790
8047
  migrationsDir: MIGRATIONS_DIR,
7791
- hooksDir: path33.join(dataDir2, "hooks"),
8048
+ hooksDir: path34.join(dataDir2, "hooks"),
7792
8049
  dev: true
7793
8050
  });
7794
8051
  pbProc = started.proc;
@@ -7814,12 +8071,12 @@ var preview = new Command73("preview").description("preview the built app").conf
7814
8071
  });
7815
8072
 
7816
8073
  // src/commands/sync.ts
7817
- import path34 from "node:path";
8074
+ import path35 from "node:path";
7818
8075
  import { Command as Command74 } from "commander";
7819
8076
  var sync = new Command74("sync").description("sync types from the database").configureHelp(helpConfig).action(
7820
8077
  () => runCommand(async () => {
7821
8078
  const { workspaceRootDir } = await getWorkspace();
7822
- const typesDir = path34.join(workspaceRootDir, ".svelte-kit", "types");
8079
+ const typesDir = path35.join(workspaceRootDir, ".svelte-kit", "types");
7823
8080
  const { processTypes } = await import("@velastack/pocketbase-codegen");
7824
8081
  await withPocketbase(workspaceRootDir, async (pb) => {
7825
8082
  await processTypes(pb, typesDir);
@@ -7832,11 +8089,11 @@ var sync = new Command74("sync").description("sync types from the database").con
7832
8089
  import { Command as Command75 } from "commander";
7833
8090
  import * as p41 from "@clack/prompts";
7834
8091
  import pc17 from "picocolors";
7835
- import * as v6 from "valibot";
7836
- var OptionsSchema2 = v6.object({
8092
+ import * as v7 from "valibot";
8093
+ var OptionsSchema2 = v7.object({
7837
8094
  ...SSH_OPTION_SCHEMA,
7838
- pbVersion: v6.optional(v6.string()),
7839
- nodeMajor: v6.optional(v6.string())
8095
+ pbVersion: v7.optional(v7.string()),
8096
+ nodeMajor: v7.optional(v7.string())
7840
8097
  });
7841
8098
  var provision = addSshOptions(
7842
8099
  new Command75("provision").description("prepare a server to host vela apps").argument("<target>", "SSH target \u2014 an alias from ~/.ssh/config, or user@host").configureHelp(helpConfig)
@@ -7881,22 +8138,22 @@ var provision = addSshOptions(
7881
8138
  );
7882
8139
 
7883
8140
  // src/commands/deploy.ts
7884
- import path36 from "node:path";
7885
- import fs34 from "node:fs";
8141
+ import path37 from "node:path";
8142
+ import fs35 from "node:fs";
7886
8143
  import { Command as Command76, Option as Option2 } from "commander";
7887
8144
  import * as p42 from "@clack/prompts";
7888
8145
  import pc18 from "picocolors";
7889
- import * as v7 from "valibot";
8146
+ import * as v8 from "valibot";
7890
8147
 
7891
8148
  // src/lib/pocketbase-settings.ts
7892
- import fs33 from "node:fs";
7893
- import path35 from "node:path";
8149
+ import fs34 from "node:fs";
8150
+ import path36 from "node:path";
7894
8151
  import process27 from "node:process";
7895
8152
  import PocketBase5 from "pocketbase";
7896
8153
  var COPIED_KEYS = ["appName", "senderName", "senderAddress"];
7897
8154
  async function readLocalMeta(cwd) {
7898
- const dataDir2 = path35.join(cwd, DATA_DIR);
7899
- if (!fs33.existsSync(dataDir2)) return null;
8155
+ const dataDir2 = path36.join(cwd, DATA_DIR);
8156
+ if (!fs34.existsSync(dataDir2)) return null;
7900
8157
  const email3 = process27.env.POCKETBASE_SUPERUSER_EMAIL;
7901
8158
  const password11 = process27.env.POCKETBASE_SUPERUSER_PASSWORD;
7902
8159
  if (!email3 || !password11) return null;
@@ -7905,7 +8162,7 @@ async function readLocalMeta(cwd) {
7905
8162
  const started = await startPocketbaseServe({
7906
8163
  dataDir: dataDir2,
7907
8164
  migrationsDir: MIGRATIONS_DIR,
7908
- hooksDir: path35.join(dataDir2, "hooks")
8165
+ hooksDir: path36.join(dataDir2, "hooks")
7909
8166
  });
7910
8167
  proc = started.proc;
7911
8168
  const pb = new PocketBase5(started.url);
@@ -7947,16 +8204,16 @@ async function seedRemoteMeta(session, instance, local, appURL) {
7947
8204
  }
7948
8205
 
7949
8206
  // src/commands/deploy.ts
7950
- var OptionsSchema3 = v7.object({
8207
+ var OptionsSchema3 = v8.object({
7951
8208
  ...SSH_OPTION_SCHEMA,
7952
- env: v7.optional(v7.string()),
7953
- project: v7.optional(v7.string()),
7954
- remoteDb: v7.optional(v7.boolean()),
7955
- domain: v7.optional(v7.string()),
7956
- healthPath: v7.optional(v7.string()),
7957
- keep: v7.optional(v7.string()),
7958
- pbVersion: v7.optional(v7.string()),
7959
- build: v7.optional(v7.boolean())
8209
+ env: v8.optional(v8.string()),
8210
+ project: v8.optional(v8.string()),
8211
+ remoteDb: v8.optional(v8.boolean()),
8212
+ domain: v8.optional(v8.string()),
8213
+ healthPath: v8.optional(v8.string()),
8214
+ keep: v8.optional(v8.string()),
8215
+ pbVersion: v8.optional(v8.string()),
8216
+ build: v8.optional(v8.boolean())
7960
8217
  });
7961
8218
  var deploy = addTargetOptions(
7962
8219
  new Command76("deploy").description("deploy the app").configureHelp(helpConfig),
@@ -8255,7 +8512,7 @@ async function uploadRelease(session, instance, release, entries) {
8255
8512
  }
8256
8513
  function isDirectory(target) {
8257
8514
  try {
8258
- return fs34.statSync(target).isDirectory();
8515
+ return fs35.statSync(target).isDirectory();
8259
8516
  } catch {
8260
8517
  return false;
8261
8518
  }
@@ -8263,7 +8520,7 @@ function isDirectory(target) {
8263
8520
  async function reportEmptyEnvironment(session, instance, workspaceRootDir) {
8264
8521
  const remote = await readRemoteEnv(session, instance);
8265
8522
  if (Object.keys(remote).length > 0) return;
8266
- if (!fs34.existsSync(path36.join(workspaceRootDir, ".env"))) return;
8523
+ if (!fs35.existsSync(path37.join(workspaceRootDir, ".env"))) return;
8267
8524
  p42.log.warn(
8268
8525
  `This app has no production environment variables yet.
8269
8526
 
@@ -8273,7 +8530,7 @@ ${pc18.cyan("vela env set KEY")}, or copy a file across with ${pc18.cyan("vela e
8273
8530
  }
8274
8531
 
8275
8532
  // src/commands/link.ts
8276
- import path37 from "node:path";
8533
+ import path38 from "node:path";
8277
8534
  import process28 from "node:process";
8278
8535
  import { Command as Command77 } from "commander";
8279
8536
  import * as p43 from "@clack/prompts";
@@ -8351,7 +8608,7 @@ async function promptProjectName(workspaceRootDir) {
8351
8608
  defaultValue,
8352
8609
  initialValue: defaultValue,
8353
8610
  placeholder: defaultValue,
8354
- validate: (v9) => !v9?.trim() ? "Required" : void 0
8611
+ validate: (v10) => !v10?.trim() ? "Required" : void 0
8355
8612
  });
8356
8613
  if (p43.isCancel(value)) {
8357
8614
  p43.cancel("Operation cancelled.");
@@ -8361,12 +8618,12 @@ async function promptProjectName(workspaceRootDir) {
8361
8618
  }
8362
8619
  function defaultProjectName2(workspaceRootDir) {
8363
8620
  try {
8364
- const pkg = readPackageJson(path37.join(workspaceRootDir, "package.json"));
8621
+ const pkg = readPackageJson(path38.join(workspaceRootDir, "package.json"));
8365
8622
  const name = pkg.name;
8366
8623
  if (typeof name === "string" && name.trim()) return name.trim();
8367
8624
  } catch {
8368
8625
  }
8369
- return path37.basename(workspaceRootDir);
8626
+ return path38.basename(workspaceRootDir);
8370
8627
  }
8371
8628
 
8372
8629
  // src/commands/env.ts
@@ -8497,8 +8754,8 @@ var envUnset = addTargetOptions(
8497
8754
  );
8498
8755
 
8499
8756
  // src/commands/env/import.ts
8500
- import fs35 from "node:fs";
8501
- import path38 from "node:path";
8757
+ import fs36 from "node:fs";
8758
+ import path39 from "node:path";
8502
8759
  import process30 from "node:process";
8503
8760
  import { Command as Command81 } from "commander";
8504
8761
  import * as p47 from "@clack/prompts";
@@ -8544,10 +8801,10 @@ var envImport = addTargetOptions(
8544
8801
  )
8545
8802
  );
8546
8803
  function resolve(file) {
8547
- return path38.resolve(process30.cwd(), file);
8804
+ return path39.resolve(process30.cwd(), file);
8548
8805
  }
8549
8806
  function read(resolved, shown) {
8550
- if (!fs35.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
8807
+ if (!fs36.existsSync(resolved)) throw new Error(`${shown} does not exist.`);
8551
8808
  const incoming = readLocalEnvFile(resolved);
8552
8809
  if (Object.keys(incoming).length === 0) p47.log.info(`${shown} has no variables to import.`);
8553
8810
  return incoming;
@@ -8819,8 +9076,8 @@ var admin = new Command87("admin").description("manage admin panel logins").conf
8819
9076
  import { Command as Command93 } from "commander";
8820
9077
 
8821
9078
  // src/commands/backup/create.ts
8822
- import fs36 from "node:fs";
8823
- import path39 from "node:path";
9079
+ import fs37 from "node:fs";
9080
+ import path40 from "node:path";
8824
9081
  import { Command as Command88 } from "commander";
8825
9082
  import * as p51 from "@clack/prompts";
8826
9083
  import pc26 from "picocolors";
@@ -8974,12 +9231,12 @@ Your bucket's own versioning is what protects the uploaded files.`
8974
9231
  }, "Failed to create the backup.")
8975
9232
  );
8976
9233
  async function download(ctx, key, outputDir) {
8977
- const dir = path39.resolve(ctx.workspaceRootDir, outputDir);
8978
- fs36.mkdirSync(dir, { recursive: true });
8979
- const destination = path39.join(dir, key);
9234
+ const dir = path40.resolve(ctx.workspaceRootDir, outputDir);
9235
+ fs37.mkdirSync(dir, { recursive: true });
9236
+ const destination = path40.join(dir, key);
8980
9237
  if (!ctx.session) {
8981
- fs36.copyFileSync(path39.join(ctx.workspaceRootDir, "data", "backups", key), destination);
8982
- return path39.relative(ctx.workspaceRootDir, destination);
9238
+ fs37.copyFileSync(path40.join(ctx.workspaceRootDir, "data", "backups", key), destination);
9239
+ return path40.relative(ctx.workspaceRootDir, destination);
8983
9240
  }
8984
9241
  const spinner7 = p51.spinner();
8985
9242
  spinner7.start(`Downloading ${key}`);
@@ -8990,7 +9247,7 @@ async function download(ctx, key, outputDir) {
8990
9247
  throw error;
8991
9248
  }
8992
9249
  spinner7.stop(`Downloaded ${key}`);
8993
- return path39.relative(ctx.workspaceRootDir, destination);
9250
+ return path40.relative(ctx.workspaceRootDir, destination);
8994
9251
  }
8995
9252
 
8996
9253
  // src/commands/backup/list.ts
@@ -9024,8 +9281,8 @@ Take one with ${pc27.cyan("vela backup create")}.`
9024
9281
  );
9025
9282
 
9026
9283
  // src/commands/backup/download.ts
9027
- import fs37 from "node:fs";
9028
- import path40 from "node:path";
9284
+ import fs38 from "node:fs";
9285
+ import path41 from "node:path";
9029
9286
  import { Command as Command90 } from "commander";
9030
9287
  import * as p53 from "@clack/prompts";
9031
9288
  import pc28 from "picocolors";
@@ -9052,11 +9309,11 @@ Run ${pc28.cyan("vela backup list")} to see what it does have.`
9052
9309
  Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
9053
9310
  );
9054
9311
  }
9055
- const dir = path40.resolve(ctx.workspaceRootDir, options.output);
9056
- fs37.mkdirSync(dir, { recursive: true });
9057
- const destination = path40.join(dir, key);
9312
+ const dir = path41.resolve(ctx.workspaceRootDir, options.output);
9313
+ fs38.mkdirSync(dir, { recursive: true });
9314
+ const destination = path41.join(dir, key);
9058
9315
  if (!ctx.session) {
9059
- fs37.copyFileSync(path40.join(ctx.workspaceRootDir, "data", "backups", key), destination);
9316
+ fs38.copyFileSync(path41.join(ctx.workspaceRootDir, "data", "backups", key), destination);
9060
9317
  } else {
9061
9318
  const spinner7 = p53.spinner();
9062
9319
  spinner7.start(`Downloading ${key} (${formatBytes(found.size)})`);
@@ -9070,7 +9327,7 @@ Fetch it from the bucket directly \u2014 vela does not hold its credentials.`
9070
9327
  }
9071
9328
  reportResult({
9072
9329
  summary: `Saved ${key} from ${ctx.targetName}.`,
9073
- filesCreated: [path40.relative(ctx.workspaceRootDir, destination)]
9330
+ filesCreated: [path41.relative(ctx.workspaceRootDir, destination)]
9074
9331
  });
9075
9332
  });
9076
9333
  }, "Failed to download the backup.")
@@ -9165,8 +9422,8 @@ Set one with ${pc30.cyan('vela backup schedule "0 3 * * *"')}.`
9165
9422
  var backup = new Command93("backup").description("back up the database and uploads, locally or on a target").configureHelp(helpConfig).addCommand(backupCreate).addCommand(backupList).addCommand(backupDownload).addCommand(backupDelete).addCommand(backupSchedule);
9166
9423
 
9167
9424
  // src/commands/restore.ts
9168
- import fs38 from "node:fs";
9169
- import path41 from "node:path";
9425
+ import fs39 from "node:fs";
9426
+ import path42 from "node:path";
9170
9427
  import process33 from "node:process";
9171
9428
  import { Command as Command94 } from "commander";
9172
9429
  import * as p56 from "@clack/prompts";
@@ -9187,7 +9444,7 @@ var restore = addTargetOptions(
9187
9444
  `${ctx.targetName} was deployed without a database, so there is nothing to restore.`
9188
9445
  );
9189
9446
  }
9190
- const local = source && fs38.existsSync(source) ? source : void 0;
9447
+ const local = source && fs39.existsSync(source) ? source : void 0;
9191
9448
  const key = local ? void 0 : await resolveKey(ctx, source);
9192
9449
  if (!options.yes) {
9193
9450
  await confirm12(ctx.appName, ctx.targetName, ctx.envTag, local ?? key);
@@ -9209,7 +9466,7 @@ var restore = addTargetOptions(
9209
9466
  });
9210
9467
  p56.log.success(
9211
9468
  `Restored ${pc31.cyan(`${ctx.appName} (${ctx.targetName})`)} from ${pc31.cyan(
9212
- local ? path41.basename(local) : key
9469
+ local ? path42.basename(local) : key
9213
9470
  )}.`
9214
9471
  );
9215
9472
  if (result?.storageCarriedOver) {
@@ -9275,21 +9532,21 @@ Take one with ${pc31.cyan("vela backup create")}, or pass the path to an archive
9275
9532
  }
9276
9533
  async function stage(ctx, file) {
9277
9534
  const dir = remotePaths.restoreStage(ctx.instance);
9278
- const remote = `${dir}/${path41.basename(file)}`;
9535
+ const remote = `${dir}/${path42.basename(file)}`;
9279
9536
  const spinner7 = p56.spinner();
9280
- spinner7.start(`Uploading ${path41.basename(file)}`);
9537
+ spinner7.start(`Uploading ${path42.basename(file)}`);
9281
9538
  try {
9282
9539
  await ctx.session.script(`mkdir -p "$1"`, { args: [dir] });
9283
9540
  await ctx.session.upload([file], dir);
9284
9541
  } catch (error) {
9285
- spinner7.stop(`Could not upload ${path41.basename(file)}.`);
9542
+ spinner7.stop(`Could not upload ${path42.basename(file)}.`);
9286
9543
  throw error;
9287
9544
  }
9288
- spinner7.stop(`Uploaded ${path41.basename(file)}`);
9545
+ spinner7.stop(`Uploaded ${path42.basename(file)}`);
9289
9546
  return remote;
9290
9547
  }
9291
9548
  async function confirm12(appName, targetName, envTag, from) {
9292
- const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path41.basename(from))}`;
9549
+ const what = `${pc31.cyan(`${appName} (${targetName})`)} from ${pc31.cyan(path42.basename(from))}`;
9293
9550
  if (isProd(envTag)) {
9294
9551
  const answer = await p56.text({
9295
9552
  message: `This replaces the database and uploads of ${what}. Type the app name to confirm`,
@@ -9315,11 +9572,11 @@ async function confirm12(appName, targetName, envTag, from) {
9315
9572
  import { Command as Command95 } from "commander";
9316
9573
  import * as p57 from "@clack/prompts";
9317
9574
  import pc32 from "picocolors";
9318
- import * as v8 from "valibot";
9319
- var OptionsSchema4 = v8.object({
9575
+ import * as v9 from "valibot";
9576
+ var OptionsSchema4 = v9.object({
9320
9577
  ...SSH_OPTION_SCHEMA,
9321
- json: v8.optional(v8.boolean()),
9322
- offline: v8.optional(v8.boolean())
9578
+ json: v9.optional(v9.boolean()),
9579
+ offline: v9.optional(v9.boolean())
9323
9580
  });
9324
9581
  var targets = addSshOptions(
9325
9582
  new Command95("targets").description("list the targets this project can deploy to").configureHelp(helpConfig)
@@ -9400,7 +9657,7 @@ Release and domain are shown from what this project recorded.`
9400
9657
  }
9401
9658
 
9402
9659
  // src/commands/test.ts
9403
- import path42 from "node:path";
9660
+ import path43 from "node:path";
9404
9661
  import process34 from "node:process";
9405
9662
  import { Command as Command96 } from "commander";
9406
9663
  import PocketBase6 from "pocketbase";
@@ -9408,20 +9665,20 @@ import pc33 from "picocolors";
9408
9665
  import { x as x5 } from "tinyexec";
9409
9666
  import { detect as detect7 } from "package-manager-detector";
9410
9667
  import { resolveCommand as resolveCommand7 } from "package-manager-detector/commands";
9411
- import fs39 from "node:fs";
9668
+ import fs40 from "node:fs";
9412
9669
  var testServer = new Command96("test:server").description("run server tests").allowUnknownOption(true).allowExcessArguments(true).configureHelp(helpConfig).action(async (_opts, cmd) => {
9413
9670
  const cwd = process34.cwd();
9414
9671
  const email3 = `test-${Math.random().toString(36).slice(2)}@example.com`;
9415
9672
  const password11 = "password";
9416
- const testDataDir = path42.join(cwd, "test-data");
9417
- fs39.rmSync(testDataDir, { recursive: true, force: true });
9673
+ const testDataDir = path43.join(cwd, "test-data");
9674
+ fs40.rmSync(testDataDir, { recursive: true, force: true });
9418
9675
  const { stop, url } = await launchPocketbase(cwd, {
9419
9676
  dir: testDataDir,
9420
- migrationsDir: path42.join(cwd, MIGRATIONS_DIR),
9677
+ migrationsDir: path43.join(cwd, MIGRATIONS_DIR),
9421
9678
  // The app's PocketBase hooks (slug generation, personal teams, …) are part
9422
9679
  // of its behaviour; the suite runs against the same server dev and build
9423
9680
  // start, so it loads them from the same place.
9424
- hooksDir: path42.join(cwd, DATA_DIR, "hooks"),
9681
+ hooksDir: path43.join(cwd, DATA_DIR, "hooks"),
9425
9682
  email: email3,
9426
9683
  password: password11
9427
9684
  });
@@ -9437,7 +9694,7 @@ var testServer = new Command96("test:server").description("run server tests").al
9437
9694
  if (cleanedUp) return;
9438
9695
  cleanedUp = true;
9439
9696
  stop();
9440
- fs39.rmSync(testDataDir, { recursive: true, force: true });
9697
+ fs40.rmSync(testDataDir, { recursive: true, force: true });
9441
9698
  };
9442
9699
  const cleanup = async () => {
9443
9700
  if (cleanedUp) return;
@@ -9536,8 +9793,8 @@ function stubPagesPlugin() {
9536
9793
  }
9537
9794
 
9538
9795
  // src/commands/routes.ts
9539
- import fs40 from "node:fs";
9540
- import path43 from "node:path";
9796
+ import fs41 from "node:fs";
9797
+ import path44 from "node:path";
9541
9798
  import { Command as Command97 } from "commander";
9542
9799
  var HTTP_METHODS = /* @__PURE__ */ new Set([
9543
9800
  "GET",
@@ -9551,30 +9808,30 @@ var HTTP_METHODS = /* @__PURE__ */ new Set([
9551
9808
  ]);
9552
9809
  var routes = new Command97("routes").description("list routes").configureHelp(helpConfig).action(async () => {
9553
9810
  const { workspaceRootDir, routesDir } = await getWorkspace();
9554
- const routesRoot = path43.join(workspaceRootDir, routesDir);
9811
+ const routesRoot = path44.join(workspaceRootDir, routesDir);
9555
9812
  const found = walk(routesRoot, routesRoot).filter((r) => r.methods.length > 0);
9556
9813
  found.sort((a, b) => a.urlPattern.localeCompare(b.urlPattern));
9557
9814
  printTable(found);
9558
9815
  });
9559
9816
  function walk(root, dir) {
9560
- const entries = fs40.readdirSync(dir, { withFileTypes: true });
9817
+ const entries = fs41.readdirSync(dir, { withFileTypes: true });
9561
9818
  const routes2 = [];
9562
9819
  const hasLeaf = entries.some((e) => e.isFile() && isRouteFile(e.name));
9563
9820
  if (hasLeaf) {
9564
- const id = "/" + path43.relative(root, dir).split(path43.sep).filter(Boolean).join("/");
9821
+ const id = "/" + path44.relative(root, dir).split(path44.sep).filter(Boolean).join("/");
9565
9822
  const urlPattern = id.replace(/\([^)]+\)\/?/g, "").replace(/\/$/, "") || "/";
9566
9823
  const methods = /* @__PURE__ */ new Set();
9567
9824
  for (const entry of entries) {
9568
9825
  if (!entry.isFile()) continue;
9569
9826
  if (entry.name.endsWith("+page.svelte")) methods.add("GET");
9570
9827
  if (entry.name.endsWith("+server.ts") || entry.name.endsWith("+server.js") || entry.name.endsWith("+page.server.ts") || entry.name.endsWith("+page.server.js")) {
9571
- extractMethods(path43.join(dir, entry.name)).forEach((m) => methods.add(m));
9828
+ extractMethods(path44.join(dir, entry.name)).forEach((m) => methods.add(m));
9572
9829
  }
9573
9830
  }
9574
9831
  routes2.push({ id: id || "/", urlPattern, methods: [...methods] });
9575
9832
  }
9576
9833
  for (const entry of entries) {
9577
- if (entry.isDirectory()) routes2.push(...walk(root, path43.join(dir, entry.name)));
9834
+ if (entry.isDirectory()) routes2.push(...walk(root, path44.join(dir, entry.name)));
9578
9835
  }
9579
9836
  return routes2;
9580
9837
  }
@@ -9583,7 +9840,7 @@ function isRouteFile(name) {
9583
9840
  }
9584
9841
  function extractMethods(file) {
9585
9842
  try {
9586
- const content = fs40.readFileSync(file, "utf8");
9843
+ const content = fs41.readFileSync(file, "utf8");
9587
9844
  const methods = [];
9588
9845
  const exportRegex = /export\s+(?:const|async\s+function|function)\s+(\w+)/g;
9589
9846
  let match;
@@ -9640,11 +9897,11 @@ async function runWuchale(extraArgs) {
9640
9897
  throwOnError: true
9641
9898
  });
9642
9899
  }
9643
- var extract = new Command98("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runWuchale([]));
9900
+ var extract2 = new Command98("extract").description("extract translatable strings").configureHelp(helpConfig).action(() => runWuchale([]));
9644
9901
  var watch = new Command98("watch").description("watch and extract translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--watch"]));
9645
9902
  var status2 = new Command98("status").description("show i18n status").configureHelp(helpConfig).action(() => runWuchale(["status"]));
9646
9903
  var clean = new Command98("clean").description("clean unused translatable strings").configureHelp(helpConfig).action(() => runWuchale(["--clean"]));
9647
- var i18n3 = new Command98("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
9904
+ var i18n3 = new Command98("i18n").description("i18n utilities").configureHelp(helpConfig).addCommand(extract2, { isDefault: true }).addCommand(watch).addCommand(status2).addCommand(clean);
9648
9905
 
9649
9906
  // src/commands/oauth.ts
9650
9907
  var oauth = stubCommand("oauth", "configure OAuth providers");
@@ -9666,7 +9923,7 @@ import pc35 from "picocolors";
9666
9923
 
9667
9924
  // src/lib/cms-backend.ts
9668
9925
  import { createRequire as createRequire3 } from "node:module";
9669
- import path44 from "node:path";
9926
+ import path45 from "node:path";
9670
9927
  import process36 from "node:process";
9671
9928
  import { pathToFileURL as pathToFileURL3 } from "node:url";
9672
9929
  import pc34 from "picocolors";
@@ -9674,7 +9931,7 @@ var DEFAULT_PROJECT = "default";
9674
9931
  async function loadBackendModule(root) {
9675
9932
  let entry;
9676
9933
  try {
9677
- entry = createRequire3(path44.join(root, "package.json")).resolve("@velastack/cms/backend");
9934
+ entry = createRequire3(path45.join(root, "package.json")).resolve("@velastack/cms/backend");
9678
9935
  } catch {
9679
9936
  throw new Error(
9680
9937
  `@velastack/cms is not installed in this project.
@@ -9692,8 +9949,8 @@ async function withCmsBackend(fn, cwd = process36.cwd()) {
9692
9949
  const { createCmsBackend } = await loadBackendModule(root);
9693
9950
  const dataDir2 = localDataDir(root);
9694
9951
  const backend3 = createCmsBackend({
9695
- dbPath: path44.join(dataDir2, "cms.sqlite"),
9696
- uploadDir: path44.join(dataDir2, "uploads")
9952
+ dbPath: path45.join(dataDir2, "cms.sqlite"),
9953
+ uploadDir: path45.join(dataDir2, "uploads")
9697
9954
  });
9698
9955
  try {
9699
9956
  return await fn(backend3);
@@ -9805,14 +10062,14 @@ program.hook("preAction", (_thisCommand, actionCommand) => {
9805
10062
  if (isStub(actionCommand)) return;
9806
10063
  const envRoot = findWorkspaceRoot() ?? process37.cwd();
9807
10064
  dotenv2.config({ path: nodePath.join(envRoot, ".env"), quiet: true });
9808
- const path45 = getCommandPath(actionCommand);
9809
- if (NO_BACKEND_COMMMANDS.has(path45)) return;
9810
- const top = path45.split(" ", 1)[0];
10065
+ const path46 = getCommandPath(actionCommand);
10066
+ if (NO_BACKEND_COMMMANDS.has(path46)) return;
10067
+ const top = path46.split(" ", 1)[0];
9811
10068
  if (NO_BACKEND_COMMMANDS.has(top)) return;
9812
10069
  if (!hasBackend()) {
9813
10070
  if (BACKEND_OPTIONAL_COMMANDS.has(top)) return;
9814
10071
  p61.log.error(
9815
- `${pc38.cyan(`vela ${path45}`)} needs a backend, and this project does not have one.
10072
+ `${pc38.cyan(`vela ${path46}`)} needs a backend, and this project does not have one.
9816
10073
 
9817
10074
  Static projects have no database to talk to.
9818
10075
 
@@ -9822,7 +10079,7 @@ To add a backend to this project, run ${pc38.cyan("vela bless")}.`
9822
10079
  p61.cancel("Operation failed.");
9823
10080
  process37.exit(1);
9824
10081
  }
9825
- if (SELF_CREDENTIALED_COMMANDS.has(path45)) return;
10082
+ if (SELF_CREDENTIALED_COMMANDS.has(path46)) return;
9826
10083
  if (!process37.env.POCKETBASE_SUPERUSER_EMAIL || !process37.env.POCKETBASE_SUPERUSER_PASSWORD) {
9827
10084
  p61.log.error(
9828
10085
  `PocketBase superuser credentials are required.