sv 0.16.4 → 0.16.6

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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { _ as name, a as detectPackageManager, d as Command, g as helpConfig, h as forwardExitCode, l as from, n as add, r as create, u as program, v as version } from "./engine-C5O8updH.mjs";
2
+ import { _ as name, a as detectPackageManager, d as Command, g as helpConfig, h as forwardExitCode, l as from, n as add, r as create, u as program, v as version } from "./engine-DbEL5s1q.mjs";
3
3
  import { color, resolveCommandArray } from "@sveltejs/sv-utils";
4
4
  import V from "node:process";
5
5
  import { execSync } from "node:child_process";
@@ -65,7 +65,7 @@ type BaseQuestion<Args extends OptionDefinition> = {
65
65
  };
66
66
  type Question<Args extends OptionDefinition = OptionDefinition> = BaseQuestion<Args> & (BooleanQuestion | StringQuestion | NumberQuestion | SelectQuestion<any> | MultiSelectQuestion<any>);
67
67
  type OptionDefinition = Record<string, Question<any>>;
68
- type OptionValues<Args extends OptionDefinition> = { [K in keyof Args]: Args[K] extends StringQuestion ? string : Args[K] extends BooleanQuestion ? boolean : Args[K] extends NumberQuestion ? number : Args[K] extends SelectQuestion<infer Value> ? Value : Args[K] extends MultiSelectQuestion<infer Value> ? Value[] : "ERROR: The value for this type is invalid. Ensure that the `default` value exists in `options`." };
68
+ type OptionValues<Args extends OptionDefinition> = { [K in keyof Args]: Args[K] extends StringQuestion ? string : Args[K] extends BooleanQuestion ? boolean : Args[K] extends NumberQuestion ? number : Args[K] extends SelectQuestion<infer Value> ? Value : Args[K] extends MultiSelectQuestion<infer Value> ? Value[] : Args[K] extends Question<any> ? unknown : "ERROR: The value for this type is invalid. Ensure that the `default` value exists in `options`." };
69
69
  //#endregion
70
70
  //#region src/core/workspace.d.ts
71
71
  type WorkspaceOptions<Args extends OptionDefinition> = OptionValues<Args>;
@@ -134,7 +134,7 @@ type SvApi = {
134
134
  */
135
135
  file: (path: string, edit: (content: string) => string | false) => void;
136
136
  };
137
- type Addon<Args extends OptionDefinition, Id extends string = string> = {
137
+ type Addon<Args extends OptionDefinition, Id extends string = string, Setup extends Record<string, unknown> = Record<string, unknown>> = {
138
138
  id: Id;
139
139
  alias?: string; /** one-liner shown in prompts */
140
140
  shortDescription?: string; /** link to docs/repo */
@@ -149,10 +149,11 @@ type Addon<Args extends OptionDefinition, Id extends string = string> = {
149
149
  * if (!isKit) unsupported('Requires SvelteKit');
150
150
  */
151
151
  unsupported: (reason: string) => void; /** On what official addons does this addon run after? */
152
- runsAfter: (name: keyof typeof officialAddons) => void;
152
+ runsAfter: (name: keyof typeof officialAddons) => void; /** Dynamically add an option to be prompted to the user */
153
+ addOption: <K extends Extract<keyof Setup, string>>(key: K, question: SetupOptions<Setup>[K]) => void;
153
154
  }) => MaybePromise<void>; /** Run the addon. The actual execution of the addon... Add files, edit files, etc. */
154
155
  run: (workspace: Workspace & {
155
- /** Add-on options */options: WorkspaceOptions<Args>; /** Api to interact with the workspace. */
156
+ /** Add-on options (includes dynamically added options from setup) */options: WorkspaceOptions<Args> & Record<string, unknown>; /** Api to interact with the workspace. */
156
157
  sv: SvApi;
157
158
  /** Cancel the addon at any time!
158
159
  * @example
@@ -161,13 +162,24 @@ type Addon<Args extends OptionDefinition, Id extends string = string> = {
161
162
  cancel: (reason: string) => void;
162
163
  }) => MaybePromise<void>; /** Next steps to display after the addon is run. */
163
164
  nextSteps?: (workspace: Workspace & {
164
- options: WorkspaceOptions<Args>;
165
+ options: WorkspaceOptions<Args> & Record<string, unknown>;
165
166
  }) => string[];
166
167
  };
168
+ /** Maps value types to question definitions for dynamic setup options */
169
+ type SetupOptions<T extends Record<string, unknown>> = { [K in keyof T]: BaseQuestion<any> & (T[K] extends boolean ? BooleanQuestion : T[K] extends string ? StringQuestion : T[K] extends number ? NumberQuestion : T[K] extends Array<infer V> ? MultiSelectQuestion<V> : Question<any>) };
167
170
  /**
168
171
  * The entry point for your addon, It will hold every thing! (options, setup, run, nextSteps, ...)
172
+ *
173
+ * For dynamic options added via `addOption` in setup, use the generic to get strong typing:
174
+ * ```ts
175
+ * const addon = defineAddon<{ extra: boolean }>()({ ... });
176
+ * addon.options.extra.default // boolean
177
+ * ```
169
178
  */
170
179
  declare function defineAddon<const Id extends string, Args extends OptionDefinition>(config: Addon<Args, Id>): Addon<Args, Id>;
180
+ declare function defineAddon<SetupValues extends Record<string, unknown>>(): <const Id extends string, Args extends OptionDefinition>(config: Omit<Addon<Args & SetupOptions<SetupValues>, Id, SetupValues>, "options"> & {
181
+ options: Args;
182
+ }) => Addon<Args & SetupOptions<SetupValues>, Id, SetupValues>;
171
183
  /**
172
184
  * Stage 1: Raw CLI input - what the user typed
173
185
  */
@@ -229,6 +241,7 @@ type SetupResult = {
229
241
  dependsOn: string[];
230
242
  unsupported: string[];
231
243
  runsAfter: string[];
244
+ additionalOptions: Record<string, Question>;
232
245
  };
233
246
  type AddonDefinition<Id extends string = string> = Addon<Record<string, Question<any>>, Id>;
234
247
  type MaybePromise<T> = Promise<T> | T;
@@ -8,7 +8,7 @@ import * as b$1 from "node:readline";
8
8
  import G from "node:readline";
9
9
  import { ReadStream } from "node:tty";
10
10
  import { fileURLToPath } from "node:url";
11
- import childProcess, { exec, spawn } from "node:child_process";
11
+ import childProcess, { exec, spawn, spawnSync } from "node:child_process";
12
12
  import { pipeline } from "node:stream/promises";
13
13
  import { PassThrough } from "node:stream";
14
14
  import { EventEmitter } from "node:events";
@@ -493,9 +493,9 @@ function W({ input: r = stdin, output: t = stdout, overwrite: s = !0, hideCursor
493
493
  r.off("keypress", n), e && t.write(import_src.cursor.show), r instanceof ReadStream && r.isTTY && !q$1 && r.setRawMode(!1), i.terminal = !1, i.close();
494
494
  };
495
495
  }
496
- const A = (r) => "columns" in r && typeof r.columns == "number" ? r.columns : 80, L = (r) => "rows" in r && typeof r.rows == "number" ? r.rows : 20;
497
- function B(r, t, s, e = s, i = s, n) {
498
- return wrapAnsi(t, A(r ?? stdout) - s.length, {
496
+ const A$1 = (r) => "columns" in r && typeof r.columns == "number" ? r.columns : 80, L$1 = (r) => "rows" in r && typeof r.rows == "number" ? r.rows : 20;
497
+ function B$1(r, t, s, e = s, i = s, n) {
498
+ return wrapAnsi(t, A$1(r ?? stdout) - s.length, {
499
499
  hard: !0,
500
500
  trim: !1
501
501
  }).split(`
@@ -629,7 +629,7 @@ var m = class {
629
629
  if (t !== this._prevFrame) {
630
630
  if (this.state === "initial") this.output.write(import_src.cursor.hide);
631
631
  else {
632
- const s = Y$1(this._prevFrame, t), e = L(this.output);
632
+ const s = Y$1(this._prevFrame, t), e = L$1(this.output);
633
633
  if (this.restoreCursor(), s) {
634
634
  const i = Math.max(0, s.numLinesAfter - e), n = Math.max(0, s.numLinesBefore - e);
635
635
  let o = s.lines.find((u) => u >= i);
@@ -805,7 +805,7 @@ const tt = se(), at = () => process.env.CI === "true", Tt = (t) => t.isTTY === !
805
805
  removals: c
806
806
  };
807
807
  }, F$1 = ({ cursor: t, options: i, style: s, output: r = process.stdout, maxItems: u = Number.POSITIVE_INFINITY, columnPadding: n = 0, rowPadding: a = 4 }) => {
808
- const c = A(r) - n, o = L(r), l = styleText("dim", "..."), d = Math.max(o - a, 0), g = Math.max(Math.min(u, d), 5);
808
+ const c = A$1(r) - n, o = L$1(r), l = styleText("dim", "..."), d = Math.max(o - a, 0), g = Math.max(Math.min(u, d), 5);
809
809
  let p = 0;
810
810
  t >= g - 3 && (p = Math.max(Math.min(t - g + 3, i.length - g), 0));
811
811
  let f = g < i.length && p > 0, h = g < i.length && p + g < i.length;
@@ -843,7 +843,7 @@ const le = (t) => {
843
843
  output: t.output,
844
844
  initialValue: t.initialValue ?? !0,
845
845
  render() {
846
- const r = t.withGuide ?? h$1.withGuide, u = `${P$1(this.state)} `, n = r ? `${styleText("gray", $)} ` : "", a = B(t.output, t.message, n, u), c = `${r ? `${styleText("gray", $)}
846
+ const r = t.withGuide ?? h$1.withGuide, u = `${P$1(this.state)} `, n = r ? `${styleText("gray", $)} ` : "", a = B$1(t.output, t.message, n, u), c = `${r ? `${styleText("gray", $)}
847
847
  ` : ""}${a}
848
848
  `, o = this.value ? i : s;
849
849
  switch (this.state) {
@@ -961,7 +961,7 @@ ${styleText("reset", styleText("dim", `Press ${styleText([
961
961
  ], " space ")} to select, ${styleText("gray", styleText("bgWhite", styleText("inverse", " enter ")))} to submit`))}`;
962
962
  },
963
963
  render() {
964
- const r = t.withGuide ?? h$1.withGuide, u = B(t.output, t.message, r ? `${ft(this.state)} ` : "", `${P$1(this.state)} `), n = `${r ? `${styleText("gray", $)}
964
+ const r = t.withGuide ?? h$1.withGuide, u = B$1(t.output, t.message, r ? `${ft(this.state)} ` : "", `${P$1(this.state)} `), n = `${r ? `${styleText("gray", $)}
965
965
  ` : ""}${u}
966
966
  `, a = this.value ?? [], c = (o, l) => {
967
967
  if (o.disabled) return i(o, "disabled");
@@ -971,12 +971,12 @@ ${styleText("reset", styleText("dim", `Press ${styleText([
971
971
  switch (this.state) {
972
972
  case "submit": {
973
973
  const o = this.options.filter(({ value: d }) => a.includes(d)).map((d) => i(d, "submitted")).join(styleText("dim", ", ")) || styleText("dim", "none");
974
- return `${n}${B(t.output, o, r ? `${styleText("gray", $)} ` : "")}`;
974
+ return `${n}${B$1(t.output, o, r ? `${styleText("gray", $)} ` : "")}`;
975
975
  }
976
976
  case "cancel": {
977
977
  const o = this.options.filter(({ value: d }) => a.includes(d)).map((d) => i(d, "cancelled")).join(styleText("dim", ", "));
978
978
  if (o.trim() === "") return `${n}${styleText("gray", $)}`;
979
- return `${n}${B(t.output, o, r ? `${styleText("gray", $)} ` : "")}${r ? `
979
+ return `${n}${B$1(t.output, o, r ? `${styleText("gray", $)} ` : "")}${r ? `
980
980
  ${styleText("gray", $)}` : ""}`;
981
981
  }
982
982
  case "error": {
@@ -1027,7 +1027,7 @@ ${r ? styleText("cyan", x$1) : ""}
1027
1027
  }, Ce = (t = "", i = "", s) => {
1028
1028
  const r = s?.output ?? V.stdout, u = s?.withGuide ?? h$1.withGuide, n = s?.format ?? be, a = [
1029
1029
  "",
1030
- ...Se(t, A(r) - 6, n).split(`
1030
+ ...Se(t, A$1(r) - 6, n).split(`
1031
1031
  `).map(n),
1032
1032
  ""
1033
1033
  ], c = fastStringWidth(i), o = Math.max(a.reduce((p, f) => {
@@ -1053,7 +1053,7 @@ ${styleText("gray", g + st.repeat(o + 2) + dt)}
1053
1053
  ], delay: a = tt ? 80 : 120, signal: c, ...o } = {}) => {
1054
1054
  const l = at();
1055
1055
  let d, g, p = !1, f = !1, h = "", I, m = performance.now();
1056
- const y = A(s), v = o?.styleFrame ?? _e, C = (_) => {
1056
+ const y = A$1(s), v = o?.styleFrame ?? _e, C = (_) => {
1057
1057
  const A = _ > 1 ? u ?? h$1.messages.error : r ?? h$1.messages.cancel;
1058
1058
  f = _ === 1, p && (W$1(A, _), f && typeof i == "function" && i());
1059
1059
  }, S = () => C(2), b = () => C(1), G = () => {
@@ -1136,17 +1136,17 @@ ${styleText("gray", g + st.repeat(o + 2) + dt)}
1136
1136
  output: t.output,
1137
1137
  initialValue: t.initialValue,
1138
1138
  render() {
1139
- const s = t.withGuide ?? h$1.withGuide, r = `${P$1(this.state)} `, u = `${ft(this.state)} `, n = B(t.output, t.message, u, r), a = `${s ? `${styleText("gray", $)}
1139
+ const s = t.withGuide ?? h$1.withGuide, r = `${P$1(this.state)} `, u = `${ft(this.state)} `, n = B$1(t.output, t.message, u, r), a = `${s ? `${styleText("gray", $)}
1140
1140
  ` : ""}${n}
1141
1141
  `;
1142
1142
  switch (this.state) {
1143
1143
  case "submit": {
1144
1144
  const c = s ? `${styleText("gray", $)} ` : "";
1145
- return `${a}${B(t.output, i(this.options[this.cursor], "selected"), c)}`;
1145
+ return `${a}${B$1(t.output, i(this.options[this.cursor], "selected"), c)}`;
1146
1146
  }
1147
1147
  case "cancel": {
1148
1148
  const c = s ? `${styleText("gray", $)} ` : "";
1149
- return `${a}${B(t.output, i(this.options[this.cursor], "cancelled"), c)}${s ? `
1149
+ return `${a}${B$1(t.output, i(this.options[this.cursor], "cancelled"), c)}${s ? `
1150
1150
  ${styleText("gray", $)}` : ""}`;
1151
1151
  }
1152
1152
  default: {
@@ -1192,7 +1192,7 @@ ${Bt}${r.trimStart()}`), s = 3 + stripVTControlCharacters(r.trimStart()).length)
1192
1192
  warning: (t) => q.warn(t),
1193
1193
  error: (t) => q.message(t, { symbol: styleText("red", yt) })
1194
1194
  }, Oe = (t) => t.replace(/\x1b\[(?:\d+;)*\d*[ABCDEFGHfJKSTsu]|\x1b\[(s|u)/g, ""), Pe = (t) => {
1195
- const i = t.output ?? process.stdout, s = A(i), r = styleText("gray", $), u = t.spacing ?? 1, n = 3, a = t.retainLog === !0, c = !at() && Tt(i);
1195
+ const i = t.output ?? process.stdout, s = A$1(i), r = styleText("gray", $), u = t.spacing ?? 1, n = 3, a = t.retainLog === !0, c = !at() && Tt(i);
1196
1196
  i.write(`${r}
1197
1197
  `), i.write(`${styleText("green", H)} ${t.title}
1198
1198
  `);
@@ -1348,7 +1348,7 @@ ${i ? styleText("cyan", x$1) : ""}
1348
1348
  //#endregion
1349
1349
  //#region package.json
1350
1350
  var name = "sv";
1351
- var version = "0.16.4";
1351
+ var version = "0.16.6";
1352
1352
  //#endregion
1353
1353
  //#region src/core/errors.ts
1354
1354
  var UnsupportedError = class extends Error {
@@ -1885,10 +1885,12 @@ var k = class extends Error {
1885
1885
  this.output = t;
1886
1886
  }
1887
1887
  };
1888
+ const A = /\r?\n/;
1888
1889
  const j = {
1889
1890
  timeout: void 0,
1890
1891
  persist: false
1891
1892
  };
1893
+ const M = { timeout: void 0 };
1892
1894
  const N = { windowsHide: true };
1893
1895
  function P(e) {
1894
1896
  const t = new AbortController();
@@ -2036,12 +2038,56 @@ var I = class {
2036
2038
  if (this._resolveClose) this._resolveClose();
2037
2039
  };
2038
2040
  };
2041
+ function L(e, r, i) {
2042
+ const a = {
2043
+ ...M,
2044
+ ...i
2045
+ };
2046
+ const o = cwd();
2047
+ const s = {
2048
+ windowsHide: true,
2049
+ ...a.nodeOptions
2050
+ };
2051
+ if (a.timeout !== void 0) s.timeout = a.timeout;
2052
+ s.env = y(o, s.env, a.nodePath);
2053
+ const c = D(e, r ?? [], s);
2054
+ const l = spawnSync(c.command, c.args, c.options);
2055
+ if (l.error) throw l.error;
2056
+ const u = l.stdout?.toString() ?? "";
2057
+ const d = l.stderr?.toString() ?? "";
2058
+ const f = l.status ?? void 0;
2059
+ const p = l.signal != null;
2060
+ const m = {
2061
+ stdout: u,
2062
+ stderr: d,
2063
+ get exitCode() {
2064
+ return f;
2065
+ },
2066
+ get pid() {
2067
+ return l.pid;
2068
+ },
2069
+ get killed() {
2070
+ return p;
2071
+ },
2072
+ *[Symbol.iterator]() {
2073
+ for (const e of [u, d]) {
2074
+ if (!e) continue;
2075
+ const t = e.split(A);
2076
+ if (t[t.length - 1] === "") t.pop();
2077
+ yield* t;
2078
+ }
2079
+ }
2080
+ };
2081
+ if (a.throwOnError && f !== 0 && f !== void 0) throw new k(m, m);
2082
+ return m;
2083
+ }
2039
2084
  const R = (e, t, n) => {
2040
2085
  const r = new I(e, t, n);
2041
2086
  r.spawn();
2042
2087
  return r;
2043
2088
  };
2044
2089
  const z = R;
2090
+ const B = L;
2045
2091
  //#endregion
2046
2092
  //#region ../../node_modules/.pnpm/commander@15.0.0/node_modules/commander/lib/error.js
2047
2093
  /**
@@ -5637,11 +5683,9 @@ function pipe(...pipe$1) {
5637
5683
  }
5638
5684
  //#endregion
5639
5685
  //#region src/core/config.ts
5640
- /**
5641
- * The entry point for your addon, It will hold every thing! (options, setup, run, nextSteps, ...)
5642
- */
5643
- function defineAddon(config) {
5644
- return config;
5686
+ function defineAddon(...args) {
5687
+ if (args.length === 0) return (config) => config;
5688
+ return args[0];
5645
5689
  }
5646
5690
  /**
5647
5691
  * Generates an inline error hint based on the addon source
@@ -5850,8 +5894,8 @@ var better_auth_default = defineAddon({
5850
5894
  const hasDemo = demoPassword || demoGithub;
5851
5895
  let drizzleDialect;
5852
5896
  let d1 = false;
5853
- sv.devDependency("better-auth", "~1.4.21");
5854
- sv.devDependency("@better-auth/cli", "~1.4.21");
5897
+ sv.devDependency("auth", "^1.6.23");
5898
+ sv.devDependency("better-auth", "^1.6.23");
5855
5899
  sv.file(`drizzle.config.${language}`, transforms.script(({ ast }) => {
5856
5900
  const isProp = (name, node) => node.key.type === "Identifier" && node.key.name === name;
5857
5901
  Walker.walk(ast, null, { Property(node) {
@@ -5975,6 +6019,7 @@ var better_auth_default = defineAddon({
5975
6019
  if (content) return false;
5976
6020
  return dedent`
5977
6021
  // If you see this file, you have not run the auth:schema script yet, but you should!
6022
+ export {};
5978
6023
  `;
5979
6024
  }));
5980
6025
  sv.file(`${directory.lib}/server/db/schema.${language}`, transforms.script(({ ast, js }) => {
@@ -10721,21 +10766,23 @@ async function formatFiles(options) {
10721
10766
  //#endregion
10722
10767
  //#region src/core/package-manager.ts
10723
10768
  const AGENT_NAMES = AGENTS.filter((agent) => !agent.includes("@"));
10724
- const agentOptions = AGENT_NAMES.map((pm) => ({
10725
- value: pm,
10726
- label: pm
10727
- }));
10728
- agentOptions.unshift({
10729
- label: "None",
10730
- value: void 0
10731
- });
10732
10769
  const installOption = new Option("--install <package-manager>", "installs dependencies with a specified package manager").choices(AGENT_NAMES);
10733
10770
  async function packageManagerPrompt(cwd) {
10734
10771
  const agent = (await detect({ cwd }))?.name ?? getUserAgent();
10735
10772
  if (!V.stdout.isTTY) return agent;
10736
10773
  const pm = await Ee({
10737
10774
  message: "Which package manager do you want to install dependencies with?",
10738
- options: agentOptions,
10775
+ options: [{
10776
+ label: "None",
10777
+ value: void 0
10778
+ }, ...AGENT_NAMES.map((agent) => {
10779
+ const installed = isInstalled(agent);
10780
+ return {
10781
+ value: agent,
10782
+ label: installed ? agent : color.dim(`${agent} (not installed)`),
10783
+ installed
10784
+ };
10785
+ }).sort((a, b) => Number(b.installed) - Number(a.installed))],
10739
10786
  initialValue: agent
10740
10787
  });
10741
10788
  if (R$2(pm)) {
@@ -10744,7 +10791,12 @@ async function packageManagerPrompt(cwd) {
10744
10791
  }
10745
10792
  return pm;
10746
10793
  }
10794
+ /** Returns `false` when the package manager isn't installed and the install was skipped. */
10747
10795
  async function installDependencies(agent, cwd) {
10796
+ if (!isInstalled(agent)) {
10797
+ R$1.warn(`${color.command(agent)} is not installed, skipping dependency installation.`);
10798
+ return false;
10799
+ }
10748
10800
  const task = Pe({
10749
10801
  title: `Installing dependencies with ${color.command(agent)}...`,
10750
10802
  limit: Math.ceil(V.stdout.rows / 2),
@@ -10768,12 +10820,12 @@ async function installDependencies(agent, cwd) {
10768
10820
  } catch {}
10769
10821
  if ((proc.exitCode ?? 0) === 0) {
10770
10822
  task.success(`Successfully installed dependencies with ${color.command(agent)}`);
10771
- return;
10823
+ return true;
10772
10824
  }
10773
10825
  if (agent === "pnpm" && output.join("\n").includes("ERR_PNPM_IGNORED_BUILDS")) {
10774
10826
  task.success(`Installed dependencies with ${color.command(agent)}`);
10775
10827
  R$1.warn(`Some build scripts were skipped. Run ${color.command(`${agent} approve-builds`)} to approve them.`);
10776
- return;
10828
+ return true;
10777
10829
  }
10778
10830
  task.error("Failed to install dependencies");
10779
10831
  ge("Operation failed.");
@@ -10790,6 +10842,20 @@ function getUserAgent() {
10790
10842
  const name = pmSpec.substring(0, separatorPos);
10791
10843
  return AGENTS.includes(name) ? name : void 0;
10792
10844
  }
10845
+ const installedCache = /* @__PURE__ */ new Map();
10846
+ function isInstalled(agent) {
10847
+ let installed = installedCache.get(agent);
10848
+ if (installed === void 0) {
10849
+ try {
10850
+ B(agent, ["--version"], { nodeOptions: { stdio: "ignore" } });
10851
+ installed = true;
10852
+ } catch {
10853
+ installed = false;
10854
+ }
10855
+ installedCache.set(agent, installed);
10856
+ }
10857
+ return installed;
10858
+ }
10793
10859
  function addPnpmAllowBuilds(cwd, packageManager, ...packages) {
10794
10860
  if (packageManager !== "pnpm" || packages.length === 0) return;
10795
10861
  const found = up$1("pnpm-workspace.yaml", { cwd });
@@ -11224,7 +11290,7 @@ const create = new Command("create").description("Scaffold a new project (--add
11224
11290
  V.exit(1);
11225
11291
  }
11226
11292
  runCommand(async () => {
11227
- const { directory, addOnNextSteps, packageManager } = await createProject(cwd, options);
11293
+ const { directory, addOnNextSteps, packageManager, depsInstalled } = await createProject(cwd, options);
11228
11294
  let i = 1;
11229
11295
  const initialSteps = ["📁 Project steps", ""];
11230
11296
  const relative = path.relative(V.cwd(), directory);
@@ -11233,7 +11299,8 @@ const create = new Command("create").description("Scaffold a new project (--add
11233
11299
  const pathHasSpaces = relative.includes(" ");
11234
11300
  initialSteps.push(` ${i++}: ${color.command(`cd ${pathHasSpaces ? `"${relative}"` : relative}`)}`);
11235
11301
  }
11236
- if (!packageManager) initialSteps.push(` ${i++}: ${color.command(resolveCommandArray(pm, "install", []))}`);
11302
+ if (packageManager && !depsInstalled) initialSteps.push(` ${i++}: Install ${color.command(pm)}`);
11303
+ if (!packageManager || !depsInstalled) initialSteps.push(` ${i++}: ${color.command(resolveCommandArray(pm, "install", []))}`);
11237
11304
  const steps = [
11238
11305
  ...initialSteps,
11239
11306
  ` ${i++}: ${color.command(resolveCommandArray(pm, "run", ["dev", "--open"]))}`,
@@ -11253,6 +11320,7 @@ const create = new Command("create").description("Scaffold a new project (--add
11253
11320
  }).showHelpAfterError(true);
11254
11321
  async function createProject(cwd, options) {
11255
11322
  if (options.fromPlayground) R$1.warn("Svelte maintainers have not reviewed playgrounds for malicious code! Use at your discretion.");
11323
+ if (options.template === "addon" && options.types === "typescript") R$1.warn(`The addon template does not support TypeScript. The ${color.command("--types")} flag will be ignored.`);
11256
11324
  const promptGroupResult = await pe({
11257
11325
  directory: () => {
11258
11326
  const defaultPath = "./";
@@ -11290,8 +11358,8 @@ async function createProject(cwd, options) {
11290
11358
  });
11291
11359
  },
11292
11360
  language: (o) => {
11293
- if (options.types) return Promise.resolve(options.types);
11294
11361
  if (o.results.template === "addon") return Promise.resolve("none");
11362
+ if (options.types) return Promise.resolve(options.types);
11295
11363
  return Ee({
11296
11364
  message: "Add type checking with TypeScript?",
11297
11365
  initialValue: "typescript",
@@ -11408,18 +11476,20 @@ async function createProject(cwd, options) {
11408
11476
  updateAgent(directory, language, packageManager ?? "npm", loadedAddons);
11409
11477
  const addOnNextSteps = getNextSteps(addOnSuccessfulAddons, workspace, answers, addonSetupResults);
11410
11478
  addPnpmAllowBuilds(projectPath, packageManager, "esbuild");
11479
+ let depsInstalled = false;
11411
11480
  if (packageManager) {
11412
- await installDependencies(packageManager, projectPath);
11413
- await formatFiles({
11481
+ depsInstalled = await installDependencies(packageManager, projectPath);
11482
+ if (depsInstalled) await formatFiles({
11414
11483
  packageManager,
11415
11484
  cwd: projectPath,
11416
- filesToFormat: addOnFilesToFormat
11485
+ filesToFormat: addOnSuccessfulAddons.some((addon) => addon.addon.id === "prettier") ? ["."] : addOnFilesToFormat
11417
11486
  });
11418
11487
  }
11419
11488
  return {
11420
11489
  directory: projectPath,
11421
11490
  addOnNextSteps,
11422
- packageManager
11491
+ packageManager,
11492
+ depsInstalled
11423
11493
  };
11424
11494
  }
11425
11495
  async function createProjectFromPlayground(url, cwd) {
@@ -11711,9 +11781,9 @@ async function promptAddonQuestions({ options, loadedAddons, workspace }) {
11711
11781
  }
11712
11782
  for (const loaded of addons) answers[loaded.addon.id] ??= {};
11713
11783
  let setupResults = {};
11714
- if (addons.length > 0) setupResults = setupAddons(addons, workspace);
11784
+ if (addons.length > 0) setupResults = await setupAddons(addons, workspace);
11715
11785
  if (addons.length === 0) {
11716
- const results = setupAddons(officialAddons.map((a) => createLoadedAddon(a)), workspace);
11786
+ const results = await setupAddons(officialAddons.map((a) => createLoadedAddon(a)), workspace);
11717
11787
  const addonOptions = officialAddons.filter(({ id, hidden }) => results[id].unsupported.length === 0 && !hidden).map(({ id, homepage, shortDescription }) => ({
11718
11788
  label: id,
11719
11789
  value: id,
@@ -11733,11 +11803,11 @@ async function promptAddonQuestions({ options, loadedAddons, workspace }) {
11733
11803
  addons.push(createLoadedAddon(addon));
11734
11804
  answers[id] = {};
11735
11805
  }
11736
- setupResults = setupAddons(addons, workspace);
11806
+ setupResults = await setupAddons(addons, workspace);
11737
11807
  }
11738
11808
  const missingSetupResults = addons.filter((a) => !setupResults[a.addon.id]);
11739
11809
  if (missingSetupResults.length > 0) {
11740
- const additionalSetupResults = setupAddons(missingSetupResults, workspace);
11810
+ const additionalSetupResults = await setupAddons(missingSetupResults, workspace);
11741
11811
  Object.assign(setupResults, additionalSetupResults);
11742
11812
  }
11743
11813
  const dependencyChains = /* @__PURE__ */ new Map();
@@ -11777,7 +11847,7 @@ async function promptAddonQuestions({ options, loadedAddons, workspace }) {
11777
11847
  }
11778
11848
  const newlyAddedAddons = addons.filter((a) => !setupResults[a.addon.id]);
11779
11849
  if (newlyAddedAddons.length > 0) {
11780
- const newSetupResults = setupAddons(newlyAddedAddons, workspace);
11850
+ const newSetupResults = await setupAddons(newlyAddedAddons, workspace);
11781
11851
  Object.assign(setupResults, newSetupResults);
11782
11852
  }
11783
11853
  }
@@ -11849,7 +11919,7 @@ async function promptAddonQuestions({ options, loadedAddons, workspace }) {
11849
11919
  };
11850
11920
  }
11851
11921
  async function runAddonsApply({ answers, options, loadedAddons, setupResults, workspace, fromCommand }) {
11852
- if (!setupResults) setupResults = setupAddons(loadedAddons.length ? loadedAddons : officialAddons.map((a) => createLoadedAddon(a)), workspace);
11922
+ if (!setupResults) setupResults = await setupAddons(loadedAddons.length ? loadedAddons : officialAddons.map((a) => createLoadedAddon(a)), workspace);
11853
11923
  if (loadedAddons.length === 0) return {
11854
11924
  nextSteps: [],
11855
11925
  argsFormattedAddons: [],
@@ -11908,17 +11978,20 @@ async function runAddonsApply({ answers, options, loadedAddons, setupResults, wo
11908
11978
  if (!options.gitCheck) argsFormattedAddons.push("--no-git-check");
11909
11979
  buildAndLogArgs(packageManager, "add", argsFormattedAddons);
11910
11980
  }
11981
+ let depsInstalled = true;
11911
11982
  if (packageManager) {
11912
11983
  workspace.packageManager = packageManager;
11913
- await installDependencies(packageManager, options.cwd);
11914
- await formatFiles({
11984
+ depsInstalled = await installDependencies(packageManager, options.cwd);
11985
+ if (depsInstalled) await formatFiles({
11915
11986
  packageManager,
11916
11987
  cwd: options.cwd,
11917
11988
  filesToFormat
11918
11989
  });
11919
11990
  }
11991
+ const nextSteps = getNextSteps(successfulAddons, workspace, answers, setupResults);
11992
+ if (packageManager && !depsInstalled) nextSteps.unshift(`Install ${color.command(packageManager)}, then run ${color.command(resolveCommandArray(packageManager, "install", []))}`);
11920
11993
  return {
11921
- nextSteps: getNextSteps(successfulAddons, workspace, answers, setupResults),
11994
+ nextSteps,
11922
11995
  argsFormattedAddons,
11923
11996
  filesToFormat,
11924
11997
  successfulAddons,
@@ -12131,7 +12204,7 @@ async function add({ addons, cwd, options, packageManager = "npm" }) {
12131
12204
  loadedAddons,
12132
12205
  workspace,
12133
12206
  options,
12134
- setupResults: setupAddons(loadedAddons, workspace)
12207
+ setupResults: await setupAddons(loadedAddons, workspace)
12135
12208
  });
12136
12209
  }
12137
12210
  async function applyAddons({ loadedAddons, workspace, setupResults, options }) {
@@ -12174,29 +12247,35 @@ async function applyAddons({ loadedAddons, workspace, setupResults, options }) {
12174
12247
  };
12175
12248
  }
12176
12249
  /** Setup addons - takes LoadedAddon[] and returns setup results */
12177
- function setupAddons(loadedAddons, workspace) {
12250
+ async function setupAddons(loadedAddons, workspace) {
12178
12251
  const setupResults = {};
12179
12252
  for (const loaded of loadedAddons) {
12180
12253
  const addon = loaded.addon;
12254
+ const additionalOptions = {};
12181
12255
  const setupResult = {
12182
12256
  unsupported: [],
12183
12257
  dependsOn: [],
12184
- runsAfter: []
12258
+ runsAfter: [],
12259
+ additionalOptions
12185
12260
  };
12186
12261
  try {
12187
- addon.setup?.({
12262
+ await addon.setup?.({
12188
12263
  ...workspace,
12189
12264
  dependsOn: (name) => {
12190
12265
  setupResult.dependsOn.push(name);
12191
12266
  setupResult.runsAfter.push(name);
12192
12267
  },
12193
12268
  unsupported: (reason) => setupResult.unsupported.push(reason),
12194
- runsAfter: (name) => setupResult.runsAfter.push(name)
12269
+ runsAfter: (name) => setupResult.runsAfter.push(name),
12270
+ addOption: (key, question) => {
12271
+ additionalOptions[key] = question;
12272
+ }
12195
12273
  });
12196
12274
  } catch (err) {
12197
12275
  const msg = err instanceof Error ? err.message : String(err);
12198
12276
  throw new Error(`Add-on '${addon.id}' failed during setup: ${msg}\n\n${getErrorHint(loaded.reference.source)}`, { cause: err });
12199
12277
  }
12278
+ if (Object.keys(additionalOptions).length > 0) Object.assign(addon.options, additionalOptions);
12200
12279
  setupResults[addon.id] = setupResult;
12201
12280
  }
12202
12281
  return setupResults;
@@ -1,4 +1,4 @@
1
- import { A as StringQuestion, C as BooleanQuestion, D as OptionValues, E as OptionDefinition, O as Question, S as BaseQuestion, T as NumberQuestion, _ as SvApi, a as Addon, b as Workspace, c as AddonReference, d as ConditionDefinition, f as ConfiguredAddon, g as SetupResult, h as PreparedAddon, i as add, j as officialAddons, k as SelectQuestion, l as AddonResult, m as OptionBuilder, n as InstallOptions, o as AddonDefinition, p as LoadedAddon, r as OptionMap, s as AddonInput, t as AddonMap, u as AddonSource, v as defineAddon, w as MultiSelectQuestion, x as WorkspaceOptions, y as defineAddonOptions } from "../engine-CtSoxta7.mjs";
1
+ import { A as StringQuestion, C as BooleanQuestion, D as OptionValues, E as OptionDefinition, O as Question, S as BaseQuestion, T as NumberQuestion, _ as SvApi, a as Addon, b as Workspace, c as AddonReference, d as ConditionDefinition, f as ConfiguredAddon, g as SetupResult, h as PreparedAddon, i as add, j as officialAddons, k as SelectQuestion, l as AddonResult, m as OptionBuilder, n as InstallOptions, o as AddonDefinition, p as LoadedAddon, r as OptionMap, s as AddonInput, t as AddonMap, u as AddonSource, v as defineAddon, w as MultiSelectQuestion, x as WorkspaceOptions, y as defineAddonOptions } from "../engine-BhR6Vrxy.mjs";
2
2
 
3
3
  //#region src/create/index.d.ts
4
4
  type TemplateType = (typeof templateTypes)[number];
@@ -1,4 +1,4 @@
1
- import { c as defineAddonOptions, m as create$1, o as officialAddons, s as defineAddon, t as add, y as svDeprecated } from "../engine-C5O8updH.mjs";
1
+ import { c as defineAddonOptions, m as create$1, o as officialAddons, s as defineAddon, t as add, y as svDeprecated } from "../engine-DbEL5s1q.mjs";
2
2
  //#region src/index.ts
3
3
  function create(cwdOrOptions, legacyOptions) {
4
4
  if (typeof cwdOrOptions === "string") {
@@ -1,4 +1,4 @@
1
- import { r as OptionMap, t as AddonMap } from "../engine-CtSoxta7.mjs";
1
+ import { r as OptionMap, t as AddonMap } from "../engine-BhR6Vrxy.mjs";
2
2
  import { Page } from "@playwright/test";
3
3
  import { TestProject } from "vitest/node";
4
4
 
@@ -1,4 +1,4 @@
1
- import { S as __toESM, b as __commonJSMin, f as R, i as addPnpmAllowBuilds, m as create, p as z, t as add, x as __require } from "../engine-C5O8updH.mjs";
1
+ import { S as __toESM, b as __commonJSMin, f as R, i as addPnpmAllowBuilds, m as create, p as z, t as add, x as __require } from "../engine-DbEL5s1q.mjs";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import V from "node:process";
@@ -22,11 +22,11 @@
22
22
  "access": "public"
23
23
  },
24
24
  "peerDependencies": {
25
- "sv": "^0.16.4"
25
+ "sv": "^0.16.6"
26
26
  },
27
27
  "devDependencies": {
28
- "sv": "^0.16.4",
29
- "@sveltejs/sv-utils": "^0.3.1",
28
+ "sv": "^0.16.6",
29
+ "@sveltejs/sv-utils": "^0.3.2",
30
30
  "@playwright/test": "^1.60.0",
31
31
  "@types/node": "^25.9.1",
32
32
  "tsdown": "^0.22.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sv",
3
- "version": "0.16.4",
3
+ "version": "0.16.6",
4
4
  "type": "module",
5
5
  "description": "A command line interface (CLI) for creating and maintaining Svelte applications",
6
6
  "license": "MIT",
@@ -25,7 +25,7 @@
25
25
  }
26
26
  },
27
27
  "dependencies": {
28
- "@sveltejs/sv-utils": "0.3.1"
28
+ "@sveltejs/sv-utils": "0.3.2"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@clack/prompts": "1.5.0",