create-krispya 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -1,32 +1,35 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- const module$1 = require('module');
5
- const process$1 = require('process');
6
- const path = require('path');
7
- const promises = require('fs/promises');
8
- const fs = require('fs');
9
- const commander = require('commander');
10
4
  const p = require('@clack/prompts');
11
5
  const color = require('chalk');
6
+ const commander = require('commander');
7
+ const node_fs = require('node:fs');
8
+ const promises$1 = require('node:fs/promises');
9
+ const node_module = require('node:module');
10
+ const node_path = require('node:path');
11
+ const node_process = require('node:process');
12
12
  const undici = require('undici');
13
13
  const child_process = require('child_process');
14
14
  const index = require('./chunks/index.cjs');
15
15
  const Conf = require('conf');
16
+ const promises = require('fs/promises');
17
+ const fs = require('fs');
18
+ const path = require('path');
16
19
 
17
20
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
18
21
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
19
22
 
20
23
  function _interopNamespaceCompat(e) {
21
- if (e && typeof e === 'object' && 'default' in e) return e;
22
- const n = Object.create(null);
23
- if (e) {
24
- for (const k in e) {
25
- n[k] = e[k];
24
+ if (e && typeof e === 'object' && 'default' in e) return e;
25
+ const n = Object.create(null);
26
+ if (e) {
27
+ for (const k in e) {
28
+ n[k] = e[k];
29
+ }
26
30
  }
27
- }
28
- n.default = e;
29
- return n;
31
+ n.default = e;
32
+ return n;
30
33
  }
31
34
 
32
35
  const p__namespace = /*#__PURE__*/_interopNamespaceCompat(p);
@@ -85,11 +88,19 @@ function formatConfigSummary(options, inherited) {
85
88
  } else {
86
89
  lines.push(formatRow("Bundler", "vite"));
87
90
  }
88
- const nodeVersionInherited = inherited?.nodeVersion !== void 0;
89
- lines.push(formatRow("Node version", options.nodeVersion || "latest", nodeVersionInherited));
91
+ const engineInherited = inherited?.engine !== void 0;
92
+ lines.push(
93
+ formatRow(
94
+ "Engine",
95
+ `${index.getEngineName(options.engine)}@${options.engine?.version ?? "latest"}`,
96
+ engineInherited
97
+ )
98
+ );
90
99
  const pmInherited = inherited?.packageManager !== void 0;
91
- lines.push(formatRow("Package manager", options.packageManager || "pnpm", pmInherited));
92
- if (options.packageManager === "pnpm") {
100
+ lines.push(
101
+ formatRow("Package manager", index.getPackageManagerName(options.packageManager), pmInherited)
102
+ );
103
+ if (index.getPackageManagerName(options.packageManager) === "pnpm") {
93
104
  const versionManaged = options.pnpmManageVersions ? "yes" : "no";
94
105
  const pnpmVersionInherited = inherited?.pnpmManageVersions !== void 0;
95
106
  lines.push(formatRow("\u21B3 Version managed", versionManaged, pnpmVersionInherited, ""));
@@ -143,8 +154,10 @@ function formatMonorepoConfigSummary(options) {
143
154
  const dots = color__default.gray(".".repeat(dotCount));
144
155
  return `${indent}${label} ${dots} ${value}`;
145
156
  };
146
- lines.push(formatRow("Node version", options.nodeVersion || "latest"));
147
- lines.push(formatRow("Package manager", options.packageManager || "pnpm"));
157
+ lines.push(
158
+ formatRow("Engine", `${index.getEngineName(options.engine)}@${options.engine.version ?? "latest"}`)
159
+ );
160
+ lines.push(formatRow("Package manager", options.packageManager));
148
161
  if (options.packageManager === "pnpm") {
149
162
  const versionManaged = options.pnpmManageVersions ? "yes" : "no";
150
163
  lines.push(formatRow("\u21B3 Version managed", versionManaged, ""));
@@ -172,9 +185,6 @@ function setReuseWindow(reuse) {
172
185
  function getAiPlatforms() {
173
186
  return config.get("aiPlatforms");
174
187
  }
175
- function setAiPlatforms(platforms) {
176
- config.set("aiPlatforms", platforms);
177
- }
178
188
  function getConfigStrategy() {
179
189
  return config.get("configStrategy") ?? "stealth";
180
190
  }
@@ -195,9 +205,9 @@ function getDefaultOptions(template, name, projectType = "app", libraryBundler,
195
205
  template,
196
206
  projectType,
197
207
  libraryBundler: projectType === "library" ? libraryBundler ?? "unbuild" : void 0,
198
- packageManager: inheritedSettings?.packageManager ?? "pnpm",
208
+ packageManager: inheritedSettings?.packageManager ?? { name: "pnpm" },
199
209
  pnpmManageVersions: inheritedSettings?.pnpmManageVersions ?? true,
200
- nodeVersion: inheritedSettings?.nodeVersion ?? "latest",
210
+ engine: inheritedSettings?.engine ?? { name: "node", version: "latest" },
201
211
  linter: inheritedSettings?.linter ?? "oxlint",
202
212
  formatter: inheritedSettings?.formatter ?? "prettier",
203
213
  // Libraries get vitest by default, apps don't
@@ -292,14 +302,14 @@ async function promptForCustomization(template, name, projectType, integrations,
292
302
  }
293
303
  libraryBundler = bundler;
294
304
  }
295
- let nodeVersion = inheritedSettings?.nodeVersion ?? presets?.nodeVersion ?? "latest";
296
- let finalPackageManager = inheritedSettings?.packageManager ?? presets?.packageManager ?? "pnpm";
305
+ let engine = inheritedSettings?.engine ?? presets?.engine ?? { name: "node", version: "latest" };
306
+ let finalPackageManager = inheritedSettings?.packageManager?.name ?? presets?.packageManager ?? "pnpm";
297
307
  let pnpmManageVersions = inheritedSettings?.pnpmManageVersions ?? presets?.pnpmManageVersions ?? true;
298
- if (!inheritedSettings?.nodeVersion) {
308
+ if (!inheritedSettings?.engine?.version) {
299
309
  const nodeVersionInput = await p__namespace.text({
300
310
  message: "Node.js version",
301
- placeholder: presets?.nodeVersion ?? "latest",
302
- defaultValue: presets?.nodeVersion ?? "latest",
311
+ placeholder: presets?.engine?.version ?? "latest",
312
+ defaultValue: presets?.engine?.version ?? "latest",
303
313
  validate: (value) => {
304
314
  if (!value.length) return "Required";
305
315
  if (value !== "latest" && !/^\d+(\.\d+(\.\d+)?)?$/.test(value)) {
@@ -311,7 +321,7 @@ async function promptForCustomization(template, name, projectType, integrations,
311
321
  p__namespace.cancel("Operation cancelled.");
312
322
  process.exit(0);
313
323
  }
314
- nodeVersion = nodeVersionInput;
324
+ engine = { name: "node", version: nodeVersionInput };
315
325
  }
316
326
  if (!inheritedSettings?.packageManager) {
317
327
  const packageManager = await p__namespace.select({
@@ -417,8 +427,8 @@ async function promptForCustomization(template, name, projectType, integrations,
417
427
  template: finalTemplate,
418
428
  projectType,
419
429
  libraryBundler: projectType === "library" ? libraryBundler : void 0,
420
- nodeVersion,
421
- packageManager: finalPackageManager,
430
+ engine,
431
+ packageManager: { name: finalPackageManager },
422
432
  pnpmManageVersions,
423
433
  linter,
424
434
  formatter,
@@ -464,9 +474,9 @@ function getDefaultMonorepoOptions(name) {
464
474
  return {
465
475
  name,
466
476
  projectType: "monorepo",
467
- packageManager: "pnpm",
477
+ packageManager: { name: "pnpm" },
468
478
  pnpmManageVersions: true,
469
- nodeVersion: "latest",
479
+ engine: { name: "node", version: "latest" },
470
480
  linter: "oxlint",
471
481
  formatter: "prettier"
472
482
  };
@@ -474,8 +484,8 @@ function getDefaultMonorepoOptions(name) {
474
484
  async function promptForMonorepoCustomization(name, presets) {
475
485
  const nodeVersion = await p__namespace.text({
476
486
  message: "Node.js version",
477
- placeholder: presets?.nodeVersion ?? "latest",
478
- defaultValue: presets?.nodeVersion ?? "latest",
487
+ placeholder: presets?.engine?.version ?? "latest",
488
+ defaultValue: presets?.engine?.version ?? "latest",
479
489
  validate: (value) => {
480
490
  if (!value.length) return "Required";
481
491
  if (value !== "latest" && !/^\d+(\.\d+(\.\d+)?)?$/.test(value)) {
@@ -524,8 +534,8 @@ async function promptForMonorepoCustomization(name, presets) {
524
534
  return {
525
535
  name,
526
536
  projectType: "monorepo",
527
- nodeVersion,
528
- packageManager: "pnpm",
537
+ engine: { name: "node", version: nodeVersion },
538
+ packageManager: { name: "pnpm" },
529
539
  pnpmManageVersions: managePnpm,
530
540
  linter,
531
541
  formatter
@@ -536,15 +546,15 @@ async function promptForMonorepo(workspaceName, presets) {
536
546
  if (presets) {
537
547
  if (presets.linter) defaultOptions.linter = presets.linter;
538
548
  if (presets.formatter) defaultOptions.formatter = presets.formatter;
539
- if (presets.nodeVersion) defaultOptions.nodeVersion = presets.nodeVersion;
549
+ if (presets.engine) defaultOptions.engine = presets.engine;
540
550
  if (presets.pnpmManageVersions !== void 0)
541
551
  defaultOptions.pnpmManageVersions = presets.pnpmManageVersions;
542
552
  }
543
553
  p__namespace.note(
544
554
  formatMonorepoConfigSummary({
545
555
  name: defaultOptions.name,
546
- nodeVersion: defaultOptions.nodeVersion ?? "latest",
547
- packageManager: defaultOptions.packageManager ?? "pnpm",
556
+ engine: defaultOptions.engine ?? { name: "node", version: "latest" },
557
+ packageManager: index.getPackageManagerName(defaultOptions.packageManager),
548
558
  pnpmManageVersions: defaultOptions.pnpmManageVersions,
549
559
  linter: defaultOptions.linter ?? "oxlint",
550
560
  formatter: defaultOptions.formatter ?? "prettier"
@@ -601,12 +611,7 @@ async function promptForOptions(name, presets) {
601
611
  if (projectType === "monorepo") {
602
612
  return promptForMonorepo(projectName, presets);
603
613
  }
604
- return promptForPackageOptions(
605
- projectName,
606
- projectType,
607
- void 0,
608
- presets
609
- );
614
+ return promptForPackageOptions(projectName, projectType, void 0, presets);
610
615
  }
611
616
  function customTemplateToOptions(customTemplate, name, projectType, inheritedSettings) {
612
617
  const baseTemplate = customTemplate.baseTemplate;
@@ -615,9 +620,9 @@ function customTemplateToOptions(customTemplate, name, projectType, inheritedSet
615
620
  name,
616
621
  template,
617
622
  projectType,
618
- packageManager: inheritedSettings?.packageManager ?? "pnpm",
623
+ packageManager: inheritedSettings?.packageManager ?? { name: "pnpm" },
619
624
  pnpmManageVersions: inheritedSettings?.pnpmManageVersions ?? true,
620
- nodeVersion: inheritedSettings?.nodeVersion ?? "latest",
625
+ engine: inheritedSettings?.engine ?? { name: "node", version: "latest" },
621
626
  linter: inheritedSettings?.linter ?? customTemplate.linter,
622
627
  formatter: inheritedSettings?.formatter ?? customTemplate.formatter,
623
628
  testing: customTemplate.testing,
@@ -648,8 +653,8 @@ function presetsToInheritedSettings(presets) {
648
653
  return {
649
654
  linter: presets.linter,
650
655
  formatter: presets.formatter,
651
- packageManager: presets.packageManager,
652
- nodeVersion: presets.nodeVersion,
656
+ packageManager: presets.packageManager ? { name: presets.packageManager } : void 0,
657
+ engine: presets.engine,
653
658
  pnpmManageVersions: presets.pnpmManageVersions
654
659
  };
655
660
  }
@@ -751,53 +756,9 @@ async function promptForPackageOptions(projectName, projectType, inheritedSettin
751
756
  );
752
757
  }
753
758
 
754
- async function checkAnyExists(paths) {
755
- for (const path of paths) {
756
- try {
757
- await promises.access(path, promises.constants.F_OK);
758
- return true;
759
- } catch {
760
- }
761
- }
762
- return false;
763
- }
764
- async function validateWorkspace(monorepoRoot) {
765
- const errors = [];
766
- const tsConfigPath = path.join(monorepoRoot, ".config/typescript/package.json");
767
- try {
768
- await promises.access(tsConfigPath, promises.constants.F_OK);
769
- } catch {
770
- errors.push("Missing .config/typescript package");
771
- }
772
- const linterPaths = [
773
- path.join(monorepoRoot, ".config/oxlint/package.json"),
774
- path.join(monorepoRoot, ".config/eslint/package.json"),
775
- path.join(monorepoRoot, "eslint.config.js"),
776
- path.join(monorepoRoot, "biome.json")
777
- ];
778
- const hasLinter = await checkAnyExists(linterPaths);
779
- if (!hasLinter) {
780
- errors.push(
781
- "Missing linter config (.config/oxlint, .config/eslint, eslint.config.js, or biome.json)"
782
- );
783
- }
784
- const formatterPaths = [
785
- path.join(monorepoRoot, ".config/oxfmt/package.json"),
786
- path.join(monorepoRoot, ".config/prettier/package.json"),
787
- path.join(monorepoRoot, ".prettierrc.json"),
788
- path.join(monorepoRoot, "biome.json")
789
- ];
790
- const hasFormatter = await checkAnyExists(formatterPaths);
791
- if (!hasFormatter) {
792
- errors.push(
793
- "Missing formatter config (.config/oxfmt, .config/prettier, .prettierrc.json, or biome.json)"
794
- );
795
- }
796
- return { valid: errors.length === 0, errors };
797
- }
798
-
799
- async function detectCurrentConfig(root) {
759
+ async function detectCurrentConfig(root, isMonorepo = true) {
800
760
  let name = root.split(/[/\\]/).pop() ?? "workspace";
761
+ let packageManager = "pnpm";
801
762
  try {
802
763
  const pkgPath = path.join(root, "package.json");
803
764
  const content = await promises.readFile(pkgPath, "utf-8");
@@ -805,47 +766,63 @@ async function detectCurrentConfig(root) {
805
766
  if (pkgJson.name) {
806
767
  name = pkgJson.name.replace(/^@/, "").replace(/\/.*$/, "");
807
768
  }
769
+ if (pkgJson.packageManager) {
770
+ packageManager = pkgJson.packageManager.split("@")[0] ?? packageManager;
771
+ }
808
772
  } catch {
809
773
  }
810
774
  const tooling = await index.detectTooling(root);
775
+ const configStrategy = isMonorepo ? void 0 : await detectStandaloneConfigStrategy(root);
811
776
  return {
812
777
  name,
813
778
  linter: tooling.linter ?? "oxlint",
814
779
  formatter: tooling.formatter ?? "prettier",
815
- packageManager: "pnpm"
780
+ packageManager,
781
+ isMonorepo,
782
+ configStrategy
816
783
  };
817
784
  }
818
- function generateExpectedFiles(config) {
819
- const { name, linter, formatter, packageManager } = config;
785
+ async function detectStandaloneConfigStrategy(root) {
786
+ const hasStealthConfig = await Promise.all([
787
+ fileExists$1(path.join(root, ".config/tsconfig.app.json")),
788
+ fileExists$1(path.join(root, ".config/tsconfig.node.json")),
789
+ fileExists$1(path.join(root, ".config/prettier.json")),
790
+ fileExists$1(path.join(root, ".config/oxlint.json"))
791
+ ]).then((matches) => matches.some(Boolean));
792
+ return hasStealthConfig ? "stealth" : "root";
793
+ }
794
+ async function generateExpectedFiles(config) {
795
+ const { name, linter, formatter, packageManager, isMonorepo, configStrategy } = config;
796
+ const versions = linter === "biome" || formatter === "biome" ? await index.resolveMonorepoRootPackageVersions({ linter, formatter }) : {};
820
797
  const aiFilesMap = {};
821
798
  index.generateAiFiles(aiFilesMap, {
822
799
  name,
823
800
  packageManager,
824
801
  linter,
825
802
  formatter,
826
- isMonorepo: true,
803
+ isMonorepo,
804
+ configStrategy,
827
805
  platforms: index.ALL_AI_PLATFORMS
828
806
  });
829
807
  const vscodeFiles = {};
830
808
  index.generateVscodeFiles(vscodeFiles, linter, formatter);
831
809
  const configPackages = {};
832
- index.generateTypescriptConfigPackage(configPackages);
833
- if (linter === "oxlint") {
834
- index.generateOxlintConfigPackage(configPackages);
835
- } else if (linter === "eslint") {
836
- index.generateEslintConfigPackage(configPackages);
837
- }
838
- if (formatter === "oxfmt") {
839
- index.generateOxfmtConfigPackage(configPackages);
840
- } else if (formatter === "prettier") {
841
- index.generatePrettierConfigPackage(configPackages);
810
+ if (isMonorepo) {
811
+ index.generateTypescriptConfigPackage(configPackages);
812
+ if (linter === "oxlint") {
813
+ index.generateOxlintConfigPackage(configPackages);
814
+ } else if (linter === "eslint") {
815
+ index.generateEslintConfigPackage(configPackages);
816
+ }
817
+ if (formatter === "oxfmt") {
818
+ index.generateOxfmtConfigPackage(configPackages);
819
+ } else if (formatter === "prettier") {
820
+ index.generatePrettierConfigPackage(configPackages);
821
+ }
842
822
  }
843
823
  const workspaceConfig = {};
844
824
  const rootConfig = {};
845
- rootConfig[".gitignore"] = {
846
- type: "text",
847
- content: ["node_modules", "dist", "*.tsbuildinfo", ".DS_Store"].join("\n")
848
- };
825
+ rootConfig[".gitignore"] = index.generateGitignore(isMonorepo ? "workspace-root" : "standalone");
849
826
  rootConfig[".gitattributes"] = {
850
827
  type: "text",
851
828
  content: `* text=auto eol=lf
@@ -854,8 +831,9 @@ function generateExpectedFiles(config) {
854
831
  `
855
832
  };
856
833
  if (linter === "biome" || formatter === "biome") {
834
+ const biomeVersion = index.getResolvedPackageVersion(versions, "@biomejs/biome");
857
835
  const biomeConfig = {
858
- $schema: "https://biomejs.dev/schemas/1.9.4/schema.json",
836
+ $schema: `https://biomejs.dev/schemas/${biomeVersion}/schema.json`,
859
837
  vcs: {
860
838
  enabled: true,
861
839
  clientKind: "git",
@@ -989,9 +967,7 @@ onlyBuiltDependencies:
989
967
  }
990
968
  if (!currentContent.includes(".config/*") && !currentContent.includes('".config/*"')) {
991
969
  const lines = updatedContent.split("\n");
992
- const packagesIndex = lines.findIndex(
993
- (line) => line.trim().startsWith("packages:")
994
- );
970
+ const packagesIndex = lines.findIndex((line) => line.trim().startsWith("packages:"));
995
971
  if (packagesIndex !== -1) {
996
972
  lines.splice(packagesIndex + 1, 0, ' - ".config/*"');
997
973
  updatedContent = lines.join("\n");
@@ -1057,6 +1033,14 @@ function needsMigration(current, target) {
1057
1033
  async function getMigrationPlan(current, target, root) {
1058
1034
  const toLinter = target.linter ?? current.linter;
1059
1035
  const toFormatter = target.formatter ?? current.formatter;
1036
+ const targetVersions = toLinter === "biome" || toFormatter === "biome" ? await index.resolveMonorepoRootPackageVersions({
1037
+ linter: toLinter,
1038
+ formatter: toFormatter
1039
+ }) : {};
1040
+ const biomeSchemaUrl = toLinter === "biome" || toFormatter === "biome" ? `https://biomejs.dev/schemas/${index.getResolvedPackageVersion(
1041
+ targetVersions,
1042
+ "@biomejs/biome"
1043
+ )}/schema.json` : "";
1060
1044
  const changes = [];
1061
1045
  if (toLinter !== current.linter) {
1062
1046
  if (current.linter !== "biome") {
@@ -1091,7 +1075,7 @@ async function getMigrationPlan(current, target, root) {
1091
1075
  description: "Add biome.json config",
1092
1076
  content: JSON.stringify(
1093
1077
  {
1094
- $schema: "https://biomejs.dev/schemas/1.9.4/schema.json",
1078
+ $schema: biomeSchemaUrl,
1095
1079
  vcs: { enabled: true, clientKind: "git", useIgnoreFile: true },
1096
1080
  linter: { enabled: true, rules: { recommended: true } },
1097
1081
  formatter: { enabled: true }
@@ -1107,7 +1091,7 @@ async function getMigrationPlan(current, target, root) {
1107
1091
  description: "Add biome.json config (linter only)",
1108
1092
  content: JSON.stringify(
1109
1093
  {
1110
- $schema: "https://biomejs.dev/schemas/1.9.4/schema.json",
1094
+ $schema: biomeSchemaUrl,
1111
1095
  vcs: { enabled: true, clientKind: "git", useIgnoreFile: true },
1112
1096
  linter: { enabled: true, rules: { recommended: true } },
1113
1097
  formatter: { enabled: false }
@@ -1160,7 +1144,7 @@ async function getMigrationPlan(current, target, root) {
1160
1144
  description: "Add biome.json config (formatter only)",
1161
1145
  content: JSON.stringify(
1162
1146
  {
1163
- $schema: "https://biomejs.dev/schemas/1.9.4/schema.json",
1147
+ $schema: biomeSchemaUrl,
1164
1148
  vcs: { enabled: true, clientKind: "git", useIgnoreFile: true },
1165
1149
  linter: { enabled: false },
1166
1150
  formatter: { enabled: true }
@@ -1183,12 +1167,7 @@ async function getMigrationPlan(current, target, root) {
1183
1167
  path: "package.json",
1184
1168
  description: "Update root package.json (devDependencies, scripts)"
1185
1169
  });
1186
- const subPackageUpdates = await getSubPackageUpdates(
1187
- root,
1188
- current,
1189
- toLinter,
1190
- toFormatter
1191
- );
1170
+ const subPackageUpdates = await getSubPackageUpdates(root, current, toLinter, toFormatter);
1192
1171
  return {
1193
1172
  fromLinter: current.linter,
1194
1173
  toLinter,
@@ -1298,23 +1277,15 @@ async function updateRootPackageJson(root, plan) {
1298
1277
  const oldFormatterDep = FORMATTER_DEPS[plan.fromFormatter];
1299
1278
  delete devDeps[oldFormatterDep];
1300
1279
  }
1280
+ const resolvedVersions = await index.resolveMonorepoRootPackageVersions({
1281
+ linter: plan.toLinter,
1282
+ formatter: plan.toFormatter
1283
+ });
1301
1284
  const newLinterDep = LINTER_DEPS[plan.toLinter];
1302
- if (plan.toLinter === "oxlint") {
1303
- devDeps[newLinterDep] = "^1.36.0";
1304
- } else if (plan.toLinter === "eslint") {
1305
- devDeps[newLinterDep] = "^9.17.0";
1306
- } else if (plan.toLinter === "biome") {
1307
- devDeps[newLinterDep] = "^1.9.4";
1308
- }
1285
+ devDeps[newLinterDep] = index.formatResolvedPackageVersion(resolvedVersions, newLinterDep);
1309
1286
  if (plan.toFormatter !== plan.toLinter) {
1310
1287
  const newFormatterDep = FORMATTER_DEPS[plan.toFormatter];
1311
- if (plan.toFormatter === "oxfmt") {
1312
- devDeps[newFormatterDep] = "^0.21.0";
1313
- } else if (plan.toFormatter === "prettier") {
1314
- devDeps[newFormatterDep] = "^3.4.2";
1315
- } else if (plan.toFormatter === "biome") {
1316
- devDeps[newFormatterDep] = "^1.9.4";
1317
- }
1288
+ devDeps[newFormatterDep] = index.formatResolvedPackageVersion(resolvedVersions, newFormatterDep);
1318
1289
  }
1319
1290
  pkg.devDependencies = Object.fromEntries(
1320
1291
  Object.entries(devDeps).sort(([a], [b]) => a.localeCompare(b))
@@ -1358,7 +1329,52 @@ function formatMigrationChange(change) {
1358
1329
  return ` ${icon} ${change.description}`;
1359
1330
  }
1360
1331
 
1361
- const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)));
1332
+ async function checkAnyExists(paths) {
1333
+ for (const path of paths) {
1334
+ try {
1335
+ await promises.access(path, promises.constants.F_OK);
1336
+ return true;
1337
+ } catch {
1338
+ }
1339
+ }
1340
+ return false;
1341
+ }
1342
+ async function validateWorkspace(monorepoRoot) {
1343
+ const errors = [];
1344
+ const tsConfigPath = path.join(monorepoRoot, ".config/typescript/package.json");
1345
+ try {
1346
+ await promises.access(tsConfigPath, promises.constants.F_OK);
1347
+ } catch {
1348
+ errors.push("Missing .config/typescript package");
1349
+ }
1350
+ const linterPaths = [
1351
+ path.join(monorepoRoot, ".config/oxlint/package.json"),
1352
+ path.join(monorepoRoot, ".config/eslint/package.json"),
1353
+ path.join(monorepoRoot, "eslint.config.js"),
1354
+ path.join(monorepoRoot, "biome.json")
1355
+ ];
1356
+ const hasLinter = await checkAnyExists(linterPaths);
1357
+ if (!hasLinter) {
1358
+ errors.push(
1359
+ "Missing linter config (.config/oxlint, .config/eslint, eslint.config.js, or biome.json)"
1360
+ );
1361
+ }
1362
+ const formatterPaths = [
1363
+ path.join(monorepoRoot, ".config/oxfmt/package.json"),
1364
+ path.join(monorepoRoot, ".config/prettier/package.json"),
1365
+ path.join(monorepoRoot, ".prettierrc.json"),
1366
+ path.join(monorepoRoot, "biome.json")
1367
+ ];
1368
+ const hasFormatter = await checkAnyExists(formatterPaths);
1369
+ if (!hasFormatter) {
1370
+ errors.push(
1371
+ "Missing formatter config (.config/oxfmt, .config/prettier, .prettierrc.json, or biome.json)"
1372
+ );
1373
+ }
1374
+ return { valid: errors.length === 0, errors };
1375
+ }
1376
+
1377
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)));
1362
1378
  const pkg = require$1("../package.json");
1363
1379
  const META_OPTIONS = [
1364
1380
  "clearConfig",
@@ -1378,7 +1394,7 @@ function hasConfigOptions(options) {
1378
1394
  }
1379
1395
  async function fileExists(path) {
1380
1396
  try {
1381
- await promises.access(path, fs.constants.F_OK);
1397
+ await promises$1.access(path, node_fs.constants.F_OK);
1382
1398
  return true;
1383
1399
  } catch {
1384
1400
  return false;
@@ -1409,7 +1425,7 @@ async function promptForAiPlatforms(isNonInteractive) {
1409
1425
  label: index.AI_PLATFORM_LABELS[platform],
1410
1426
  hint: index.AI_PLATFORM_HINTS[platform]
1411
1427
  })),
1412
- initialValues: [],
1428
+ initialValues: ["agents"],
1413
1429
  required: false
1414
1430
  });
1415
1431
  if (p__namespace.isCancel(selected)) {
@@ -1419,26 +1435,19 @@ async function promptForAiPlatforms(isNonInteractive) {
1419
1435
  if (platforms.length === 0) {
1420
1436
  return [];
1421
1437
  }
1422
- const saveChoice = await p__namespace.confirm({
1423
- message: "Save selection for future projects?",
1424
- initialValue: true
1425
- });
1426
- if (!p__namespace.isCancel(saveChoice) && saveChoice) {
1427
- setAiPlatforms(platforms);
1428
- }
1429
1438
  return platforms;
1430
1439
  }
1431
1440
  async function writeGeneratedFiles(basePath, files) {
1432
1441
  const filePaths = Object.keys(files).sort();
1433
1442
  for (const filePath of filePaths) {
1434
- const fullFilePath = path.join(basePath, filePath);
1435
- await promises.mkdir(path.dirname(fullFilePath), { recursive: true });
1443
+ const fullFilePath = node_path.join(basePath, filePath);
1444
+ await promises$1.mkdir(node_path.dirname(fullFilePath), { recursive: true });
1436
1445
  const file = files[filePath];
1437
1446
  if (file.type === "text") {
1438
- await promises.writeFile(fullFilePath, file.content);
1447
+ await promises$1.writeFile(fullFilePath, file.content);
1439
1448
  } else {
1440
1449
  const response = await undici.fetch(file.url);
1441
- await promises.writeFile(fullFilePath, response.body);
1450
+ await promises$1.writeFile(fullFilePath, response.body);
1442
1451
  }
1443
1452
  }
1444
1453
  }
@@ -1447,26 +1456,37 @@ function calculateWorkspaceRoot(packagePath) {
1447
1456
  return segments.map(() => "..").join("/");
1448
1457
  }
1449
1458
  async function detectMonorepoRoot() {
1450
- let currentDir = process$1.cwd();
1451
- const root = path.resolve("/");
1459
+ let currentDir = node_process.cwd();
1460
+ const root = node_path.resolve("/");
1452
1461
  while (currentDir !== root) {
1453
- const workspaceFile = path.join(currentDir, "pnpm-workspace.yaml");
1462
+ const workspaceFile = node_path.join(currentDir, "pnpm-workspace.yaml");
1454
1463
  try {
1455
- await promises.access(workspaceFile, fs.constants.F_OK);
1456
- const content = await promises.readFile(workspaceFile, "utf-8");
1464
+ await promises$1.access(workspaceFile, node_fs.constants.F_OK);
1465
+ const content = await promises$1.readFile(workspaceFile, "utf-8");
1457
1466
  if (content.includes("packages:")) {
1458
1467
  return currentDir;
1459
1468
  }
1460
1469
  } catch {
1461
1470
  }
1462
- currentDir = path.dirname(currentDir);
1471
+ currentDir = node_path.dirname(currentDir);
1463
1472
  }
1464
1473
  return null;
1465
1474
  }
1475
+ async function detectPackageRoot() {
1476
+ let currentDir = node_process.cwd();
1477
+ const root = node_path.resolve("/");
1478
+ while (currentDir !== root) {
1479
+ if (await fileExists(node_path.join(currentDir, "package.json"))) {
1480
+ return currentDir;
1481
+ }
1482
+ currentDir = node_path.dirname(currentDir);
1483
+ }
1484
+ return await fileExists(node_path.join(root, "package.json")) ? root : null;
1485
+ }
1466
1486
  async function parseWorkspaceDirectories(monorepoRoot) {
1467
1487
  try {
1468
- const workspaceFile = path.join(monorepoRoot, "pnpm-workspace.yaml");
1469
- const content = await promises.readFile(workspaceFile, "utf-8");
1488
+ const workspaceFile = node_path.join(monorepoRoot, "pnpm-workspace.yaml");
1489
+ const content = await promises$1.readFile(workspaceFile, "utf-8");
1470
1490
  return index.parseWorkspaceYamlContent(content);
1471
1491
  } catch {
1472
1492
  return [];
@@ -1475,34 +1495,23 @@ async function parseWorkspaceDirectories(monorepoRoot) {
1475
1495
  async function detectWorkspaceSettings(monorepoRoot) {
1476
1496
  try {
1477
1497
  const tooling = await index.detectTooling(monorepoRoot);
1478
- const pkgPath = path.join(monorepoRoot, "package.json");
1479
- const content = await promises.readFile(pkgPath, "utf-8");
1498
+ const pkgPath = node_path.join(monorepoRoot, "package.json");
1499
+ const content = await promises$1.readFile(pkgPath, "utf-8");
1480
1500
  const pkgJson = JSON.parse(content);
1481
- let packageManager;
1482
- if (pkgJson.packageManager) {
1483
- packageManager = pkgJson.packageManager.split("@")[0];
1484
- }
1485
- let nodeVersion;
1486
- if (pkgJson.engines?.node) {
1487
- const match = pkgJson.engines.node.match(/(\d+)/);
1488
- if (match) {
1489
- nodeVersion = match[1];
1490
- }
1491
- }
1501
+ const packageManager = index.parsePackageManager(pkgJson.packageManager);
1502
+ const engine = index.parseEngine(pkgJson.engines);
1492
1503
  let pnpmManageVersions;
1493
1504
  try {
1494
- const workspaceFile = path.join(monorepoRoot, "pnpm-workspace.yaml");
1495
- const workspaceContent = await promises.readFile(workspaceFile, "utf-8");
1496
- pnpmManageVersions = workspaceContent.includes(
1497
- "manage-package-manager-versions: true"
1498
- );
1505
+ const workspaceFile = node_path.join(monorepoRoot, "pnpm-workspace.yaml");
1506
+ const workspaceContent = await promises$1.readFile(workspaceFile, "utf-8");
1507
+ pnpmManageVersions = workspaceContent.includes("manage-package-manager-versions: true");
1499
1508
  } catch {
1500
1509
  }
1501
1510
  return {
1502
1511
  linter: tooling.linter,
1503
1512
  formatter: tooling.formatter,
1504
1513
  packageManager,
1505
- nodeVersion,
1514
+ engine,
1506
1515
  pnpmManageVersions
1507
1516
  };
1508
1517
  } catch {
@@ -1511,17 +1520,17 @@ async function detectWorkspaceSettings(monorepoRoot) {
1511
1520
  }
1512
1521
  async function detectExistingConfigs(monorepoRoot) {
1513
1522
  const configs = {};
1514
- const eslintPath = path.join(monorepoRoot, "eslint.config.js");
1523
+ const eslintPath = node_path.join(monorepoRoot, "eslint.config.js");
1515
1524
  if (await fileExists(eslintPath)) {
1516
1525
  configs.linter = "eslint";
1517
1526
  configs.eslintConfigPath = eslintPath;
1518
1527
  }
1519
- const prettierPath = path.join(monorepoRoot, ".prettierrc.json");
1528
+ const prettierPath = node_path.join(monorepoRoot, ".prettierrc.json");
1520
1529
  if (await fileExists(prettierPath)) {
1521
1530
  configs.formatter = "prettier";
1522
1531
  configs.prettierConfigPath = prettierPath;
1523
1532
  }
1524
- const biomePath = path.join(monorepoRoot, "biome.json");
1533
+ const biomePath = node_path.join(monorepoRoot, "biome.json");
1525
1534
  if (await fileExists(biomePath)) {
1526
1535
  configs.biomeConfigPath = biomePath;
1527
1536
  if (!configs.linter) configs.linter = "biome";
@@ -1531,8 +1540,8 @@ async function detectExistingConfigs(monorepoRoot) {
1531
1540
  }
1532
1541
  async function getMonorepoScope(monorepoRoot) {
1533
1542
  try {
1534
- const pkgPath = path.join(monorepoRoot, "package.json");
1535
- const content = await promises.readFile(pkgPath, "utf-8");
1543
+ const pkgPath = node_path.join(monorepoRoot, "package.json");
1544
+ const content = await promises$1.readFile(pkgPath, "utf-8");
1536
1545
  const pkgJson = JSON.parse(content);
1537
1546
  if (pkgJson.name) {
1538
1547
  return pkgJson.name.replace(/^@/, "").replace(/\/.*$/, "");
@@ -1542,7 +1551,7 @@ async function getMonorepoScope(monorepoRoot) {
1542
1551
  return monorepoRoot.split(/[/\\]/).pop() ?? "workspace";
1543
1552
  }
1544
1553
  async function getWorkspacePackages(monorepoRoot) {
1545
- const packagesDir = path.join(monorepoRoot, "packages");
1554
+ const packagesDir = node_path.join(monorepoRoot, "packages");
1546
1555
  try {
1547
1556
  const { readdir } = await import('fs/promises');
1548
1557
  const entries = await readdir(packagesDir, { withFileTypes: true });
@@ -1550,8 +1559,8 @@ async function getWorkspacePackages(monorepoRoot) {
1550
1559
  for (const entry of entries) {
1551
1560
  if (!entry.isDirectory()) continue;
1552
1561
  try {
1553
- const content = await promises.readFile(
1554
- path.join(packagesDir, entry.name, "package.json"),
1562
+ const content = await promises$1.readFile(
1563
+ node_path.join(packagesDir, entry.name, "package.json"),
1555
1564
  "utf-8"
1556
1565
  );
1557
1566
  const pkg2 = JSON.parse(content);
@@ -1565,25 +1574,23 @@ async function getWorkspacePackages(monorepoRoot) {
1565
1574
  }
1566
1575
  }
1567
1576
  async function ensureConfigInWorkspace(monorepoRoot) {
1568
- const workspacePath = path.join(monorepoRoot, "pnpm-workspace.yaml");
1577
+ const workspacePath = node_path.join(monorepoRoot, "pnpm-workspace.yaml");
1569
1578
  let content;
1570
1579
  try {
1571
- content = await promises.readFile(workspacePath, "utf-8");
1580
+ content = await promises$1.readFile(workspacePath, "utf-8");
1572
1581
  } catch {
1573
1582
  content = `packages:
1574
1583
  - ".config/*"
1575
1584
  - "packages/*"
1576
1585
  `;
1577
- await promises.writeFile(workspacePath, content);
1586
+ await promises$1.writeFile(workspacePath, content);
1578
1587
  return;
1579
1588
  }
1580
1589
  if (content.includes(".config/*") || content.includes('".config/*"')) {
1581
1590
  return;
1582
1591
  }
1583
1592
  const lines = content.split("\n");
1584
- const packagesIndex = lines.findIndex(
1585
- (line) => line.trim().startsWith("packages:")
1586
- );
1593
+ const packagesIndex = lines.findIndex((line) => line.trim().startsWith("packages:"));
1587
1594
  if (packagesIndex === -1) {
1588
1595
  content = `packages:
1589
1596
  - ".config/*"
@@ -1592,14 +1599,14 @@ ${content}`;
1592
1599
  lines.splice(packagesIndex + 1, 0, ' - ".config/*"');
1593
1600
  content = lines.join("\n");
1594
1601
  }
1595
- await promises.writeFile(workspacePath, content);
1602
+ await promises$1.writeFile(workspacePath, content);
1596
1603
  }
1597
1604
  async function migrateEslintConfig(monorepoRoot, files) {
1598
1605
  const configBasePath = ".config/eslint";
1599
- const existingConfigPath = path.join(monorepoRoot, "eslint.config.js");
1606
+ const existingConfigPath = node_path.join(monorepoRoot, "eslint.config.js");
1600
1607
  let existingContent;
1601
1608
  try {
1602
- existingContent = await promises.readFile(existingConfigPath, "utf-8");
1609
+ existingContent = await promises$1.readFile(existingConfigPath, "utf-8");
1603
1610
  } catch {
1604
1611
  index.generateEslintConfigPackage(files);
1605
1612
  return;
@@ -1675,10 +1682,10 @@ export default [
1675
1682
  }
1676
1683
  async function migratePrettierConfig(monorepoRoot, files) {
1677
1684
  const configBasePath = ".config/prettier";
1678
- const existingConfigPath = path.join(monorepoRoot, ".prettierrc.json");
1685
+ const existingConfigPath = node_path.join(monorepoRoot, ".prettierrc.json");
1679
1686
  let existingContent;
1680
1687
  try {
1681
- existingContent = await promises.readFile(existingConfigPath, "utf-8");
1688
+ existingContent = await promises$1.readFile(existingConfigPath, "utf-8");
1682
1689
  } catch {
1683
1690
  index.generatePrettierConfigPackage(files);
1684
1691
  return;
@@ -1748,7 +1755,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
1748
1755
  const dirName = value.includes("/") ? value.split("/").pop() : value;
1749
1756
  if (!dirName) return "Package name is required";
1750
1757
  if (!hasCustomDirectories) {
1751
- const targetPath = path.join(monorepoRoot, defaultDir, dirName);
1758
+ const targetPath = node_path.join(monorepoRoot, defaultDir, dirName);
1752
1759
  try {
1753
1760
  const { statSync } = require$1("fs");
1754
1761
  statSync(targetPath);
@@ -1763,11 +1770,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
1763
1770
  }
1764
1771
  const scopedName = packageNameInput;
1765
1772
  const shortName = scopedName.includes("/") ? scopedName.split("/").pop() : scopedName;
1766
- const packageOptions = await promptForPackageOptions(
1767
- scopedName,
1768
- packageType,
1769
- inheritedSettings
1770
- );
1773
+ const packageOptions = await promptForPackageOptions(scopedName, packageType, inheritedSettings);
1771
1774
  let targetDir = defaultDir;
1772
1775
  if (hasCustomDirectories && workspaceDirectories.length > 0) {
1773
1776
  const dirChoice = await p__namespace.select({
@@ -1782,7 +1785,7 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
1782
1785
  return false;
1783
1786
  }
1784
1787
  targetDir = dirChoice;
1785
- const targetPath = path.join(monorepoRoot, targetDir, shortName);
1788
+ const targetPath = node_path.join(monorepoRoot, targetDir, shortName);
1786
1789
  try {
1787
1790
  const { statSync } = require$1("fs");
1788
1791
  statSync(targetPath);
@@ -1791,81 +1794,13 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
1791
1794
  } catch {
1792
1795
  }
1793
1796
  }
1794
- const relativePkgPath = path.join(targetDir, shortName);
1797
+ const relativePkgPath = node_path.join(targetDir, shortName);
1795
1798
  const workspaceRoot = calculateWorkspaceRoot(relativePkgPath);
1796
1799
  packageOptions.workspaceRoot = workspaceRoot;
1797
1800
  packageOptions.name = scopedName;
1798
- if (packageManager === "pnpm") {
1799
- packageOptions.pnpmVersion = await index.getLatestPnpmVersion();
1800
- } else if (packageManager === "yarn") {
1801
- packageOptions.yarnVersion = await index.getLatestYarnVersion();
1802
- } else if (packageManager === "npm") {
1803
- packageOptions.npmVersion = await index.getLatestNpmCliVersion();
1804
- }
1805
- const nodeVersion = packageOptions.nodeVersion ?? "latest";
1806
- if (nodeVersion === "latest") {
1807
- packageOptions.nodeVersion = await index.getLatestNodeVersion();
1808
- }
1809
- const versions = {};
1810
- const versionPromises = [];
1811
- const pkgIsLibrary = packageOptions.projectType === "library";
1812
- const pkgTesting = packageOptions.testing ?? (pkgIsLibrary ? "vitest" : "none");
1813
- if (pkgTesting === "vitest") {
1814
- versionPromises.push(
1815
- index.getLatestNpmVersion("vitest", "4.0.0").then((v) => {
1816
- versions.vitest = v;
1817
- })
1818
- );
1819
- }
1820
- if (!pkgIsLibrary) {
1821
- versionPromises.push(
1822
- index.getLatestNpmVersion("vite", "6.3.4").then((v) => {
1823
- versions.vite = v;
1824
- })
1825
- );
1826
- }
1827
- const linter = packageOptions.linter ?? "oxlint";
1828
- if (linter === "eslint") {
1829
- versionPromises.push(
1830
- index.getLatestNpmVersion("eslint", "9.17.0").then((v) => {
1831
- versions.eslint = v;
1832
- })
1833
- );
1834
- } else if (linter === "oxlint") {
1835
- versionPromises.push(
1836
- index.getLatestNpmVersion("oxlint", "0.16.0").then((v) => {
1837
- versions.oxlint = v;
1838
- })
1839
- );
1840
- } else if (linter === "biome") {
1841
- versionPromises.push(
1842
- index.getLatestNpmVersion("@biomejs/biome", "1.9.4").then((v) => {
1843
- versions.biome = v;
1844
- })
1845
- );
1846
- }
1847
- const formatter = packageOptions.formatter ?? "prettier";
1848
- if (formatter === "prettier") {
1849
- versionPromises.push(
1850
- index.getLatestNpmVersion("prettier", "3.4.2").then((v) => {
1851
- versions.prettier = v;
1852
- })
1853
- );
1854
- } else if (formatter === "oxfmt") {
1855
- versionPromises.push(
1856
- index.getLatestNpmVersion("oxfmt", "0.1.0").then((v) => {
1857
- versions.oxfmt = v;
1858
- })
1859
- );
1860
- } else if (formatter === "biome" && linter !== "biome") {
1861
- versionPromises.push(
1862
- index.getLatestNpmVersion("@biomejs/biome", "1.9.4").then((v) => {
1863
- versions.biome = v;
1864
- })
1865
- );
1866
- }
1867
- await Promise.all(versionPromises);
1868
- packageOptions.versions = versions;
1801
+ packageOptions.packageManager = await index.resolvePackageManager(packageOptions);
1802
+ packageOptions.engine = await index.resolveEngine(packageOptions);
1803
+ packageOptions.versions = await index.resolveProjectPackageVersions(packageOptions);
1869
1804
  const workspacePackages = packageType === "app" ? await getWorkspacePackages(monorepoRoot) : [];
1870
1805
  if (workspacePackages.length > 0) {
1871
1806
  const selectedDeps = await p__namespace.multiselect({
@@ -1877,15 +1812,13 @@ async function createPackageInWorkspace(monorepoRoot, packageManager, inheritedS
1877
1812
  packageOptions.workspaceDependencies = selectedDeps;
1878
1813
  }
1879
1814
  }
1880
- const outputPath = path.join(monorepoRoot, relativePkgPath);
1815
+ const outputPath = node_path.join(monorepoRoot, relativePkgPath);
1881
1816
  const spinner = p__namespace.spinner();
1882
1817
  spinner.start("Creating package...");
1883
1818
  try {
1884
1819
  const files = index.generate(packageOptions);
1885
1820
  await writeGeneratedFiles(outputPath, files);
1886
- spinner.stop(
1887
- color__default.green.inverse(` \u2713 Package created at ${relativePkgPath}! `)
1888
- );
1821
+ spinner.stop(color__default.green.inverse(` \u2713 Package created at ${relativePkgPath}! `));
1889
1822
  const addAnother = await p__namespace.select({
1890
1823
  message: "Add another package?",
1891
1824
  options: [
@@ -2063,19 +1996,17 @@ async function handleFixCommand(options) {
2063
1996
  try {
2064
1997
  const files = {};
2065
1998
  const tsConfigExists = await fileExists(
2066
- path.join(monorepoRoot, ".config/typescript/package.json")
1999
+ node_path.join(monorepoRoot, ".config/typescript/package.json")
2067
2000
  );
2068
2001
  if (!tsConfigExists) {
2069
2002
  index.generateTypescriptConfigPackage(files);
2070
2003
  }
2071
2004
  if (linter === "oxlint") {
2072
- const oxlintExists = await fileExists(
2073
- path.join(monorepoRoot, ".config/oxlint/package.json")
2074
- );
2005
+ const oxlintExists = await fileExists(node_path.join(monorepoRoot, ".config/oxlint/package.json"));
2075
2006
  if (!oxlintExists) index.generateOxlintConfigPackage(files);
2076
2007
  } else if (linter === "eslint") {
2077
2008
  const eslintPkgExists = await fileExists(
2078
- path.join(monorepoRoot, ".config/eslint/package.json")
2009
+ node_path.join(monorepoRoot, ".config/eslint/package.json")
2079
2010
  );
2080
2011
  if (!eslintPkgExists) {
2081
2012
  if (existingConfigs.eslintConfigPath) {
@@ -2086,13 +2017,11 @@ async function handleFixCommand(options) {
2086
2017
  }
2087
2018
  }
2088
2019
  if (formatter === "oxfmt") {
2089
- const oxfmtExists = await fileExists(
2090
- path.join(monorepoRoot, ".config/oxfmt/package.json")
2091
- );
2020
+ const oxfmtExists = await fileExists(node_path.join(monorepoRoot, ".config/oxfmt/package.json"));
2092
2021
  if (!oxfmtExists) index.generateOxfmtConfigPackage(files);
2093
2022
  } else if (formatter === "prettier") {
2094
2023
  const prettierPkgExists = await fileExists(
2095
- path.join(monorepoRoot, ".config/prettier/package.json")
2024
+ node_path.join(monorepoRoot, ".config/prettier/package.json")
2096
2025
  );
2097
2026
  if (!prettierPkgExists) {
2098
2027
  if (existingConfigs.prettierConfigPath) {
@@ -2103,8 +2032,13 @@ async function handleFixCommand(options) {
2103
2032
  }
2104
2033
  }
2105
2034
  if ((linter === "biome" || formatter === "biome") && !existingConfigs.biomeConfigPath) {
2035
+ const versions = await index.resolveMonorepoRootPackageVersions({
2036
+ linter,
2037
+ formatter
2038
+ });
2039
+ const biomeVersion = index.getResolvedPackageVersion(versions, "@biomejs/biome");
2106
2040
  const biomeConfig = {
2107
- $schema: "https://biomejs.dev/schemas/1.9.4/schema.json",
2041
+ $schema: `https://biomejs.dev/schemas/${biomeVersion}/schema.json`,
2108
2042
  vcs: {
2109
2043
  enabled: true,
2110
2044
  clientKind: "git",
@@ -2126,36 +2060,32 @@ async function handleFixCommand(options) {
2126
2060
  };
2127
2061
  }
2128
2062
  for (const [filePath, file] of Object.entries(files)) {
2129
- const fullPath = path.join(monorepoRoot, filePath);
2130
- await promises.mkdir(path.dirname(fullPath), { recursive: true });
2131
- await promises.writeFile(fullPath, file.content);
2063
+ const fullPath = node_path.join(monorepoRoot, filePath);
2064
+ await promises$1.mkdir(node_path.dirname(fullPath), { recursive: true });
2065
+ await promises$1.writeFile(fullPath, file.content);
2132
2066
  }
2133
2067
  await ensureConfigInWorkspace(monorepoRoot);
2134
2068
  if (existingConfigs.eslintConfigPath && linter === "eslint") {
2135
2069
  try {
2136
- await promises.unlink(existingConfigs.eslintConfigPath);
2070
+ await promises$1.unlink(existingConfigs.eslintConfigPath);
2137
2071
  } catch {
2138
2072
  }
2139
2073
  }
2140
2074
  if (existingConfigs.prettierConfigPath && formatter === "prettier") {
2141
2075
  try {
2142
- await promises.unlink(existingConfigs.prettierConfigPath);
2076
+ await promises$1.unlink(existingConfigs.prettierConfigPath);
2143
2077
  } catch {
2144
2078
  }
2145
2079
  }
2146
2080
  spinner.stop(color__default.green("\u2713") + " Workspace fixed!");
2147
- const generated = Object.keys(files).filter(
2148
- (f) => f.endsWith("package.json")
2149
- );
2081
+ const generated = Object.keys(files).filter((f) => f.endsWith("package.json"));
2150
2082
  for (const pkgFile of generated) {
2151
2083
  const pkgName = pkgFile.replace("/package.json", "");
2152
2084
  console.log(color__default.dim(` Generated ${pkgName}`));
2153
2085
  }
2154
- const vscodeSettingsExists = await fileExists(
2155
- path.join(monorepoRoot, ".vscode/settings.json")
2156
- );
2086
+ const vscodeSettingsExists = await fileExists(node_path.join(monorepoRoot, ".vscode/settings.json"));
2157
2087
  const vscodeExtensionsExists = await fileExists(
2158
- path.join(monorepoRoot, ".vscode/extensions.json")
2088
+ node_path.join(monorepoRoot, ".vscode/extensions.json")
2159
2089
  );
2160
2090
  const vscodeExists = vscodeSettingsExists && vscodeExtensionsExists;
2161
2091
  if (!vscodeExists) {
@@ -2173,17 +2103,15 @@ async function handleFixCommand(options) {
2173
2103
  const vscodeFiles = {};
2174
2104
  index.generateVscodeFiles(vscodeFiles, linter, formatter);
2175
2105
  for (const [filePath, file] of Object.entries(vscodeFiles)) {
2176
- const fullPath = path.join(monorepoRoot, filePath);
2177
- await promises.mkdir(path.dirname(fullPath), { recursive: true });
2178
- await promises.writeFile(fullPath, file.content);
2106
+ const fullPath = node_path.join(monorepoRoot, filePath);
2107
+ await promises$1.mkdir(node_path.dirname(fullPath), { recursive: true });
2108
+ await promises$1.writeFile(fullPath, file.content);
2179
2109
  }
2180
2110
  console.log(color__default.dim(" Generated .vscode/settings.json"));
2181
2111
  console.log(color__default.dim(" Generated .vscode/extensions.json"));
2182
2112
  }
2183
2113
  }
2184
- const aiRulesExist = await fileExists(
2185
- path.join(monorepoRoot, ".ai/workspace.md")
2186
- );
2114
+ const aiRulesExist = await fileExists(node_path.join(monorepoRoot, ".ai/workspace.md"));
2187
2115
  if (!aiRulesExist) {
2188
2116
  const platforms = await promptForAiPlatforms(isNonInteractive);
2189
2117
  if (platforms.length > 0) {
@@ -2198,9 +2126,9 @@ async function handleFixCommand(options) {
2198
2126
  platforms
2199
2127
  });
2200
2128
  for (const [filePath, file] of Object.entries(aiFilesOutput)) {
2201
- const fullPath = path.join(monorepoRoot, filePath);
2202
- await promises.mkdir(path.dirname(fullPath), { recursive: true });
2203
- await promises.writeFile(fullPath, file.content);
2129
+ const fullPath = node_path.join(monorepoRoot, filePath);
2130
+ await promises$1.mkdir(node_path.dirname(fullPath), { recursive: true });
2131
+ await promises$1.writeFile(fullPath, file.content);
2204
2132
  console.log(color__default.dim(` Generated ${filePath}`));
2205
2133
  }
2206
2134
  }
@@ -2216,15 +2144,11 @@ async function handleMigration(config, target, root, options) {
2216
2144
  const plan = await getMigrationPlan(config, target, root);
2217
2145
  console.log(color__default.cyan("Migration:"));
2218
2146
  if (plan.fromLinter !== plan.toLinter) {
2219
- console.log(
2220
- ` Linter: ${color__default.dim(plan.fromLinter)} \u2192 ${color__default.green(plan.toLinter)}`
2221
- );
2147
+ console.log(` Linter: ${color__default.dim(plan.fromLinter)} \u2192 ${color__default.green(plan.toLinter)}`);
2222
2148
  }
2223
2149
  if (plan.fromFormatter !== plan.toFormatter) {
2224
2150
  console.log(
2225
- ` Formatter: ${color__default.dim(plan.fromFormatter)} \u2192 ${color__default.green(
2226
- plan.toFormatter
2227
- )}`
2151
+ ` Formatter: ${color__default.dim(plan.fromFormatter)} \u2192 ${color__default.green(plan.toFormatter)}`
2228
2152
  );
2229
2153
  }
2230
2154
  console.log();
@@ -2255,17 +2179,17 @@ async function handleMigration(config, target, root, options) {
2255
2179
  }
2256
2180
  }
2257
2181
  await applyMigration(plan, root);
2258
- const aiWorkspacePath = path.join(root, ".ai/workspace.md");
2182
+ const aiWorkspacePath = node_path.join(root, ".ai/workspace.md");
2259
2183
  const aiRulesExist = await fileExists(aiWorkspacePath);
2260
2184
  if (aiRulesExist) {
2261
2185
  console.log();
2262
2186
  console.log(color__default.cyan("Updating AI rules..."));
2263
2187
  const scope = await getMonorepoScope(root);
2264
2188
  const existingPlatforms = [];
2265
- if (await fileExists(path.join(root, "AGENTS.md"))) {
2189
+ if (await fileExists(node_path.join(root, "AGENTS.md"))) {
2266
2190
  existingPlatforms.push("agents");
2267
2191
  }
2268
- if (await fileExists(path.join(root, "CLAUDE.md"))) {
2192
+ if (await fileExists(node_path.join(root, "CLAUDE.md"))) {
2269
2193
  existingPlatforms.push("claude");
2270
2194
  }
2271
2195
  const aiFilesOutput = {};
@@ -2278,94 +2202,94 @@ async function handleMigration(config, target, root, options) {
2278
2202
  platforms: existingPlatforms.length > 0 ? existingPlatforms : ["agents"]
2279
2203
  });
2280
2204
  for (const [filePath, file] of Object.entries(aiFilesOutput)) {
2281
- const fullPath = path.join(root, filePath);
2282
- await promises.mkdir(path.dirname(fullPath), { recursive: true });
2283
- await promises.writeFile(fullPath, file.content);
2205
+ const fullPath = node_path.join(root, filePath);
2206
+ await promises$1.mkdir(node_path.dirname(fullPath), { recursive: true });
2207
+ await promises$1.writeFile(fullPath, file.content);
2284
2208
  console.log(color__default.dim(` ${filePath}`));
2285
2209
  }
2286
2210
  }
2287
2211
  console.log();
2288
- console.log(
2289
- color__default.green("\u2713") + ` Migrated to ${plan.toLinter}/${plan.toFormatter}`
2290
- );
2212
+ console.log(color__default.green("\u2713") + ` Migrated to ${plan.toLinter}/${plan.toFormatter}`);
2291
2213
  console.log(color__default.dim(" Run `pnpm install` to update dependencies"));
2292
2214
  process.exit(0);
2293
2215
  }
2294
2216
  async function handleUpdateCommand(options) {
2295
2217
  const monorepoRoot = await detectMonorepoRoot();
2296
- if (!monorepoRoot) {
2297
- console.log(color__default.red("\u2717") + " Not a monorepo workspace");
2298
- console.log(color__default.dim(" --update only supports pnpm monorepos"));
2218
+ const projectRoot = monorepoRoot ?? await detectPackageRoot();
2219
+ if (!projectRoot) {
2220
+ console.log(color__default.red("\u2717") + " Could not find a project root");
2221
+ console.log(color__default.dim(" Run this command from inside a generated project"));
2299
2222
  process.exit(1);
2300
2223
  }
2301
- const { valid, errors } = await validateWorkspace(monorepoRoot);
2302
- if (!valid) {
2303
- console.log(color__default.yellow("!") + " Workspace has issues:");
2304
- for (const error of errors) {
2305
- console.log(color__default.dim(` \u2022 ${error}`));
2224
+ const isMonorepo = monorepoRoot != null;
2225
+ if (isMonorepo) {
2226
+ const { valid, errors } = await validateWorkspace(projectRoot);
2227
+ if (!valid) {
2228
+ console.log(color__default.yellow("!") + " Workspace has issues:");
2229
+ for (const error of errors) {
2230
+ console.log(color__default.dim(` \u2022 ${error}`));
2231
+ }
2232
+ console.log();
2233
+ const shouldFix = options.yes || await p__namespace.confirm({
2234
+ message: "Run fix first to resolve these issues?",
2235
+ initialValue: true
2236
+ });
2237
+ if (p__namespace.isCancel(shouldFix) || !shouldFix) {
2238
+ console.log(color__default.dim(" Run `pnpm create krispya --fix` to fix manually"));
2239
+ process.exit(1);
2240
+ }
2241
+ const preFixConfig = await detectCurrentConfig(projectRoot);
2242
+ const fixOptions = {
2243
+ ...options,
2244
+ linter: options.linter ?? preFixConfig.linter,
2245
+ formatter: options.formatter ?? preFixConfig.formatter
2246
+ };
2247
+ await handleFixCommand(fixOptions);
2306
2248
  }
2249
+ } else if (options.linter || options.formatter) {
2250
+ console.log(
2251
+ color__default.yellow("!") + " Linter/formatter migrations in --update are currently monorepo-only"
2252
+ );
2253
+ console.log(color__default.dim(" Continuing with standalone shared config updates"));
2307
2254
  console.log();
2308
- const shouldFix = options.yes || await p__namespace.confirm({
2309
- message: "Run fix first to resolve these issues?",
2310
- initialValue: true
2311
- });
2312
- if (p__namespace.isCancel(shouldFix) || !shouldFix) {
2313
- console.log(
2314
- color__default.dim(" Run `pnpm create krispya --fix` to fix manually")
2315
- );
2316
- process.exit(1);
2317
- }
2318
- const preFixConfig = await detectCurrentConfig(monorepoRoot);
2319
- const fixOptions = {
2320
- ...options,
2321
- linter: options.linter ?? preFixConfig.linter,
2322
- formatter: options.formatter ?? preFixConfig.formatter
2323
- };
2324
- await handleFixCommand(fixOptions);
2325
2255
  }
2326
- const config = await detectCurrentConfig(monorepoRoot);
2256
+ const config = await detectCurrentConfig(projectRoot, isMonorepo);
2327
2257
  const targetLinter = options.linter;
2328
2258
  const targetFormatter = options.formatter;
2329
2259
  const migrationTarget = { linter: targetLinter, formatter: targetFormatter };
2330
- if (needsMigration(config, migrationTarget)) {
2331
- await handleMigration(config, migrationTarget, monorepoRoot, options);
2260
+ if (isMonorepo && needsMigration(config, migrationTarget)) {
2261
+ await handleMigration(config, migrationTarget, projectRoot, options);
2332
2262
  return;
2333
2263
  }
2334
2264
  console.log(
2335
2265
  color__default.cyan("Checking for updates...") + color__default.dim(` (${config.linter}/${config.formatter})`)
2336
2266
  );
2337
2267
  console.log();
2338
- const expected = generateExpectedFiles(config);
2339
- const categories = await compareWithDisk(expected, monorepoRoot);
2340
- const workspaceConfigChanges = await getWorkspaceConfigUpdates(monorepoRoot);
2341
- const workspaceCategory = {
2342
- category: "workspace-config",
2343
- label: "Workspace Config",
2344
- changes: workspaceConfigChanges,
2345
- hasUserModifications: workspaceConfigChanges.some(
2346
- (c) => c.status === "modified"
2347
- )
2348
- };
2349
- const allCategories = categories.filter(
2350
- (c) => c.category !== "workspace-config"
2351
- );
2352
- if (workspaceConfigChanges.length > 0) {
2353
- const configPkgIndex = allCategories.findIndex(
2354
- (c) => c.category === "config-packages"
2355
- );
2356
- if (configPkgIndex !== -1) {
2357
- allCategories.splice(configPkgIndex + 1, 0, workspaceCategory);
2358
- } else {
2359
- allCategories.push(workspaceCategory);
2268
+ const expected = await generateExpectedFiles(config);
2269
+ const categories = await compareWithDisk(expected, projectRoot);
2270
+ const allCategories = categories.filter((c) => c.category !== "workspace-config");
2271
+ if (isMonorepo) {
2272
+ const workspaceConfigChanges = await getWorkspaceConfigUpdates(projectRoot);
2273
+ const workspaceCategory = {
2274
+ category: "workspace-config",
2275
+ label: "Workspace Config",
2276
+ changes: workspaceConfigChanges,
2277
+ hasUserModifications: workspaceConfigChanges.some((c) => c.status === "modified")
2278
+ };
2279
+ if (workspaceConfigChanges.length > 0) {
2280
+ const configPkgIndex = allCategories.findIndex((c) => c.category === "config-packages");
2281
+ if (configPkgIndex !== -1) {
2282
+ allCategories.splice(configPkgIndex + 1, 0, workspaceCategory);
2283
+ } else {
2284
+ allCategories.push(workspaceCategory);
2285
+ }
2360
2286
  }
2361
2287
  }
2362
2288
  let updatedCount = 0;
2363
2289
  let skippedCount = 0;
2364
2290
  for (const category of allCategories) {
2365
2291
  const newChanges = category.changes.filter((c) => c.status === "added");
2366
- const modifiedChanges = category.changes.filter(
2367
- (c) => c.status === "modified"
2368
- );
2292
+ const modifiedChanges = category.changes.filter((c) => c.status === "modified");
2369
2293
  const hasNew = newChanges.length > 0;
2370
2294
  const hasModified = modifiedChanges.length > 0;
2371
2295
  const hasChanges = hasNew || hasModified;
@@ -2376,19 +2300,15 @@ async function handleUpdateCommand(options) {
2376
2300
  if (category.category === "ai-files") {
2377
2301
  if (hasNew) {
2378
2302
  console.log(color__default.cyan(category.label + ":"));
2379
- console.log(
2380
- color__default.dim(` ${newChanges.length} AI file(s) can be added`)
2381
- );
2303
+ console.log(color__default.dim(` ${newChanges.length} AI file(s) can be added`));
2382
2304
  console.log();
2383
2305
  const applyAi = options.yes ? true : await p__namespace.confirm({
2384
2306
  message: "Add AI rules?",
2385
2307
  initialValue: true
2386
2308
  });
2387
2309
  if (!p__namespace.isCancel(applyAi) && applyAi) {
2388
- await applyUpdates(newChanges, monorepoRoot);
2389
- console.log(
2390
- color__default.green("\u2713") + ` Added ${newChanges.length} AI file(s)`
2391
- );
2310
+ await applyUpdates(newChanges, projectRoot);
2311
+ console.log(color__default.green("\u2713") + ` Added ${newChanges.length} AI file(s)`);
2392
2312
  updatedCount++;
2393
2313
  } else {
2394
2314
  console.log(color__default.dim(` Skipped ${category.label}`));
@@ -2409,7 +2329,7 @@ async function handleUpdateCommand(options) {
2409
2329
  initialValue: false
2410
2330
  });
2411
2331
  if (!p__namespace.isCancel(updateExisting) && updateExisting) {
2412
- await applyUpdates(modifiedChanges, monorepoRoot);
2332
+ await applyUpdates(modifiedChanges, projectRoot);
2413
2333
  console.log(color__default.green("\u2713") + " Updated existing AI files");
2414
2334
  }
2415
2335
  }
@@ -2452,9 +2372,7 @@ async function handleUpdateCommand(options) {
2452
2372
  process.exit(0);
2453
2373
  }
2454
2374
  if (selectedFiles.length > 0) {
2455
- changesToApply = allChanges.filter(
2456
- (c) => selectedFiles.includes(c.path)
2457
- );
2375
+ changesToApply = allChanges.filter((c) => selectedFiles.includes(c.path));
2458
2376
  }
2459
2377
  } else if (hasNew) {
2460
2378
  console.log(color__default.cyan(category.label + ":"));
@@ -2492,13 +2410,9 @@ async function handleUpdateCommand(options) {
2492
2410
  }
2493
2411
  }
2494
2412
  if (changesToApply.length > 0) {
2495
- await applyUpdates(changesToApply, monorepoRoot);
2496
- const addedCount = changesToApply.filter(
2497
- (c) => c.status === "added"
2498
- ).length;
2499
- const updatedFilesCount = changesToApply.filter(
2500
- (c) => c.status === "modified"
2501
- ).length;
2413
+ await applyUpdates(changesToApply, projectRoot);
2414
+ const addedCount = changesToApply.filter((c) => c.status === "added").length;
2415
+ const updatedFilesCount = changesToApply.filter((c) => c.status === "modified").length;
2502
2416
  const parts = [];
2503
2417
  if (addedCount > 0) parts.push(`added ${addedCount}`);
2504
2418
  if (updatedFilesCount > 0) parts.push(`updated ${updatedFilesCount}`);
@@ -2525,20 +2439,12 @@ async function handleUpdateCommand(options) {
2525
2439
  async function handleWorkspaceCommand(name, options) {
2526
2440
  const monorepoRoot = await detectMonorepoRoot();
2527
2441
  if (!monorepoRoot) {
2528
- console.error(
2529
- color__default.red("Error:") + " --workspace flag requires being inside a monorepo"
2530
- );
2442
+ console.error(color__default.red("Error:") + " --workspace flag requires being inside a monorepo");
2531
2443
  process.exit(1);
2532
2444
  }
2533
2445
  if (!name) {
2534
- console.error(
2535
- color__default.red("Error:") + " Package name is required with --workspace flag"
2536
- );
2537
- console.log(
2538
- color__default.dim(
2539
- " Example: pnpm create krispya my-lib --workspace --type library"
2540
- )
2541
- );
2446
+ console.error(color__default.red("Error:") + " Package name is required with --workspace flag");
2447
+ console.log(color__default.dim(" Example: pnpm create krispya my-lib --workspace --type library"));
2542
2448
  process.exit(1);
2543
2449
  }
2544
2450
  const scope = await getMonorepoScope(monorepoRoot);
@@ -2549,32 +2455,23 @@ async function handleWorkspaceCommand(name, options) {
2549
2455
  const template = options.template ?? "vanilla";
2550
2456
  const baseTemplate = index.getBaseTemplate(template);
2551
2457
  const scopedName = name.startsWith("@") ? name : `@${scope}/${name}`;
2552
- const fullPackagePath = path.join(monorepoRoot, targetDir, name);
2458
+ const fullPackagePath = node_path.join(monorepoRoot, targetDir, name);
2553
2459
  try {
2554
- await promises.access(fullPackagePath, fs.constants.F_OK);
2555
- console.error(
2556
- color__default.red("Error:") + ` Directory ${targetDir}/${name} already exists`
2557
- );
2460
+ await promises$1.access(fullPackagePath, node_fs.constants.F_OK);
2461
+ console.error(color__default.red("Error:") + ` Directory ${targetDir}/${name} already exists`);
2558
2462
  process.exit(1);
2559
2463
  } catch {
2560
2464
  }
2561
- const versions = {};
2562
- const versionPromises = [];
2563
- const isLibrary = projectType === "library";
2564
- if (!isLibrary) {
2565
- versionPromises.push(
2566
- index.getLatestNpmVersion("vite", "6.3.4").then((v) => {
2567
- versions.vite = v;
2568
- })
2569
- );
2570
- }
2571
2465
  const linter = inheritedSettings.linter ?? options.linter ?? "oxlint";
2572
2466
  const formatter = inheritedSettings.formatter ?? options.formatter ?? "prettier";
2573
- const packageManager = inheritedSettings.packageManager ?? "pnpm";
2574
- const nodeVersion = inheritedSettings.nodeVersion ?? "latest";
2467
+ const packageManager = inheritedSettings.packageManager?.name ?? "pnpm";
2468
+ const engine = inheritedSettings.engine ?? {
2469
+ name: "node",
2470
+ version: "latest"
2471
+ };
2575
2472
  const pnpmManageVersions = inheritedSettings.pnpmManageVersions ?? true;
2576
- await Promise.all(versionPromises);
2577
- const relativePkgPath = path.join(targetDir, name);
2473
+ const isLibrary = projectType === "library";
2474
+ const relativePkgPath = node_path.join(targetDir, name);
2578
2475
  const workspaceRoot = calculateWorkspaceRoot(relativePkgPath);
2579
2476
  const generateOptions = {
2580
2477
  name: scopedName,
@@ -2583,11 +2480,10 @@ async function handleWorkspaceCommand(name, options) {
2583
2480
  template,
2584
2481
  linter,
2585
2482
  formatter,
2586
- packageManager,
2587
- nodeVersion,
2483
+ packageManager: { name: packageManager },
2484
+ engine,
2588
2485
  pnpmManageVersions,
2589
2486
  workspaceRoot,
2590
- versions,
2591
2487
  ...baseTemplate === "r3f" && {
2592
2488
  drei: options.drei ? {} : void 0,
2593
2489
  handle: options.handle ? {} : void 0,
@@ -2603,15 +2499,14 @@ async function handleWorkspaceCommand(name, options) {
2603
2499
  triplex: options.triplex ? {} : void 0
2604
2500
  }
2605
2501
  };
2606
- console.log(
2607
- color__default.cyan("Creating") + ` ${scopedName} in ${targetDir}/${name}...`
2608
- );
2502
+ generateOptions.packageManager = await index.resolvePackageManager(generateOptions);
2503
+ generateOptions.engine = await index.resolveEngine(generateOptions);
2504
+ generateOptions.versions = await index.resolveProjectPackageVersions(generateOptions);
2505
+ console.log(color__default.cyan("Creating") + ` ${scopedName} in ${targetDir}/${name}...`);
2609
2506
  try {
2610
2507
  const files = index.generate(generateOptions);
2611
2508
  await writeGeneratedFiles(fullPackagePath, files);
2612
- console.log(
2613
- color__default.green("\u2713") + ` Created ${scopedName} at ${targetDir}/${name}`
2614
- );
2509
+ console.log(color__default.green("\u2713") + ` Created ${scopedName} at ${targetDir}/${name}`);
2615
2510
  process.exit(0);
2616
2511
  } catch (error) {
2617
2512
  console.error(color__default.red("Error:") + " Failed to create package");
@@ -2621,20 +2516,16 @@ async function handleWorkspaceCommand(name, options) {
2621
2516
  }
2622
2517
  async function handleMonorepoCreation(generateOptions, isNonInteractive) {
2623
2518
  const { generateMonorepo } = await import('./chunks/index.cjs').then(function (n) { return n.monorepo; });
2624
- const packageManager = generateOptions.packageManager || "pnpm";
2625
- if (packageManager === "pnpm") {
2626
- generateOptions.pnpmVersion = await index.getLatestPnpmVersion();
2627
- } else if (packageManager === "yarn") {
2628
- generateOptions.yarnVersion = await index.getLatestYarnVersion();
2629
- } else if (packageManager === "npm") {
2630
- generateOptions.npmVersion = await index.getLatestNpmCliVersion();
2631
- }
2632
- const nodeVersion = generateOptions.nodeVersion ?? "latest";
2633
- if (nodeVersion === "latest") {
2634
- generateOptions.nodeVersion = await index.getLatestNodeVersion();
2635
- }
2519
+ const packageManager = index.getPackageManagerName(generateOptions.packageManager);
2520
+ generateOptions.packageManager = await index.resolvePackageManager(generateOptions);
2521
+ generateOptions.engine = await index.resolveEngine(generateOptions);
2522
+ generateOptions.versions = await index.resolveMonorepoRootPackageVersions({
2523
+ linter: generateOptions.linter ?? "oxlint",
2524
+ formatter: generateOptions.formatter ?? "prettier",
2525
+ versions: generateOptions.versions
2526
+ });
2636
2527
  const aiPlatforms = await promptForAiPlatforms(isNonInteractive);
2637
- const projectPath = path.join(process$1.cwd(), generateOptions.name);
2528
+ const projectPath = node_path.join(node_process.cwd(), generateOptions.name);
2638
2529
  const spinner = p__namespace.spinner();
2639
2530
  spinner.start("Creating monorepo workspace...");
2640
2531
  try {
@@ -2642,19 +2533,21 @@ async function handleMonorepoCreation(generateOptions, isNonInteractive) {
2642
2533
  name: generateOptions.name,
2643
2534
  linter: generateOptions.linter ?? "oxlint",
2644
2535
  formatter: generateOptions.formatter ?? "prettier",
2645
- packageManager,
2646
- pnpmVersion: generateOptions.pnpmVersion,
2536
+ packageManager: generateOptions.packageManager ?? {
2537
+ name: packageManager
2538
+ },
2647
2539
  pnpmManageVersions: generateOptions.pnpmManageVersions,
2648
- nodeVersion: generateOptions.nodeVersion,
2540
+ engine: generateOptions.engine,
2541
+ versions: generateOptions.versions,
2649
2542
  aiPlatforms: aiPlatforms.length > 0 ? aiPlatforms : void 0
2650
2543
  });
2651
2544
  const filePaths = Object.keys(files).sort();
2652
2545
  for (const filePath of filePaths) {
2653
- const fullFilePath = path.join(projectPath, filePath);
2654
- await promises.mkdir(path.dirname(fullFilePath), { recursive: true });
2546
+ const fullFilePath = node_path.join(projectPath, filePath);
2547
+ await promises$1.mkdir(node_path.dirname(fullFilePath), { recursive: true });
2655
2548
  const file = files[filePath];
2656
2549
  if (file.type === "text") {
2657
- await promises.writeFile(fullFilePath, file.content);
2550
+ await promises$1.writeFile(fullFilePath, file.content);
2658
2551
  }
2659
2552
  }
2660
2553
  spinner.stop(color__default.green.inverse(" \u2713 Monorepo workspace created! "));
@@ -2664,8 +2557,10 @@ async function handleMonorepoCreation(generateOptions, isNonInteractive) {
2664
2557
  const newWorkspaceSettings = {
2665
2558
  linter: generateOptions.linter,
2666
2559
  formatter: generateOptions.formatter,
2667
- packageManager,
2668
- nodeVersion: generateOptions.nodeVersion,
2560
+ packageManager: generateOptions.packageManager ?? {
2561
+ name: packageManager
2562
+ },
2563
+ engine: generateOptions.engine,
2669
2564
  pnpmManageVersions: generateOptions.pnpmManageVersions
2670
2565
  };
2671
2566
  const scope = generateOptions.name;
@@ -2701,88 +2596,19 @@ async function handleStandaloneProjectCreation(generateOptions, isNonInteractive
2701
2596
  if (aiPlatforms.length > 0) {
2702
2597
  generateOptions.aiPlatforms = aiPlatforms;
2703
2598
  }
2704
- const packageManager = generateOptions.packageManager || "pnpm";
2705
- if (packageManager === "pnpm") {
2706
- generateOptions.pnpmVersion = await index.getLatestPnpmVersion();
2707
- } else if (packageManager === "yarn") {
2708
- generateOptions.yarnVersion = await index.getLatestYarnVersion();
2709
- } else if (packageManager === "npm") {
2710
- generateOptions.npmVersion = await index.getLatestNpmCliVersion();
2711
- }
2712
- const nodeVersion = generateOptions.nodeVersion ?? "latest";
2713
- if (nodeVersion === "latest") {
2714
- generateOptions.nodeVersion = await index.getLatestNodeVersion();
2715
- }
2716
- const versions = {};
2717
- const versionPromises = [];
2599
+ const packageManager = index.getPackageManagerName(generateOptions.packageManager);
2718
2600
  const isLibrary = generateOptions.projectType === "library";
2719
- const testing = generateOptions.testing ?? (isLibrary ? "vitest" : "none");
2720
- if (testing === "vitest") {
2721
- versionPromises.push(
2722
- index.getLatestNpmVersion("vitest", "4.0.0").then((v) => {
2723
- versions.vitest = v;
2724
- })
2725
- );
2726
- }
2727
- if (!isLibrary) {
2728
- versionPromises.push(
2729
- index.getLatestNpmVersion("vite", "6.3.4").then((v) => {
2730
- versions.vite = v;
2731
- })
2732
- );
2733
- }
2734
- const linter = generateOptions.linter ?? "oxlint";
2735
- if (linter === "eslint") {
2736
- versionPromises.push(
2737
- index.getLatestNpmVersion("eslint", "9.17.0").then((v) => {
2738
- versions.eslint = v;
2739
- })
2740
- );
2741
- } else if (linter === "oxlint") {
2742
- versionPromises.push(
2743
- index.getLatestNpmVersion("oxlint", "0.16.0").then((v) => {
2744
- versions.oxlint = v;
2745
- })
2746
- );
2747
- } else if (linter === "biome") {
2748
- versionPromises.push(
2749
- index.getLatestNpmVersion("@biomejs/biome", "1.9.4").then((v) => {
2750
- versions.biome = v;
2751
- })
2752
- );
2753
- }
2754
- const formatter = generateOptions.formatter ?? "prettier";
2755
- if (formatter === "prettier") {
2756
- versionPromises.push(
2757
- index.getLatestNpmVersion("prettier", "3.4.2").then((v) => {
2758
- versions.prettier = v;
2759
- })
2760
- );
2761
- } else if (formatter === "oxfmt") {
2762
- versionPromises.push(
2763
- index.getLatestNpmVersion("oxfmt", "0.1.0").then((v) => {
2764
- versions.oxfmt = v;
2765
- })
2766
- );
2767
- } else if (formatter === "biome" && linter !== "biome") {
2768
- versionPromises.push(
2769
- index.getLatestNpmVersion("@biomejs/biome", "1.9.4").then((v) => {
2770
- versions.biome = v;
2771
- })
2772
- );
2773
- }
2774
- await Promise.all(versionPromises);
2775
- generateOptions.versions = versions;
2776
- const projectPath = path.join(process$1.cwd(), generateOptions.name);
2601
+ generateOptions.packageManager = await index.resolvePackageManager(generateOptions);
2602
+ generateOptions.engine = await index.resolveEngine(generateOptions);
2603
+ generateOptions.versions = await index.resolveProjectPackageVersions(generateOptions);
2604
+ const projectPath = node_path.join(node_process.cwd(), generateOptions.name);
2777
2605
  const spinner = p__namespace.spinner();
2778
2606
  spinner.start("Creating project...");
2779
2607
  try {
2780
2608
  const files = index.generate(generateOptions);
2781
2609
  await writeGeneratedFiles(projectPath, files);
2782
2610
  spinner.stop(color__default.green.inverse(" \u2713 Project created! "));
2783
- if (isNonInteractive) {
2784
- process.exit(0);
2785
- }
2611
+ if (isNonInteractive) process.exit(0);
2786
2612
  const nextSteps = isLibrary ? [
2787
2613
  `cd ${generateOptions.name}`,
2788
2614
  `${packageManager} install`,
@@ -2821,7 +2647,7 @@ async function handleInteractiveMonorepoMode(monorepoRoot) {
2821
2647
  const settingsInfo = [
2822
2648
  inheritedSettings.linter && `linter: ${inheritedSettings.linter}`,
2823
2649
  inheritedSettings.formatter && `formatter: ${inheritedSettings.formatter}`,
2824
- inheritedSettings.packageManager && `pm: ${inheritedSettings.packageManager}`
2650
+ inheritedSettings.packageManager && `pm: ${inheritedSettings.packageManager.name}`
2825
2651
  ].filter(Boolean).join(", ");
2826
2652
  p__namespace.log.info(`Using workspace settings (${settingsInfo})`);
2827
2653
  }
@@ -2830,39 +2656,25 @@ async function handleInteractiveMonorepoMode(monorepoRoot) {
2830
2656
  while (addMore) {
2831
2657
  addMore = await createPackageInWorkspace(
2832
2658
  monorepoRoot,
2833
- inheritedSettings.packageManager ?? "pnpm",
2659
+ inheritedSettings.packageManager?.name ?? "pnpm",
2834
2660
  inheritedSettings,
2835
2661
  scope
2836
2662
  );
2837
2663
  }
2838
- p__namespace.note(
2839
- [`cd ${monorepoRoot}`, "pnpm install", "pnpm run dev"].join("\n"),
2840
- "Next steps"
2841
- );
2664
+ p__namespace.note([`cd ${monorepoRoot}`, "pnpm install", "pnpm run dev"].join("\n"), "Next steps");
2842
2665
  await promptAndOpenEditor(monorepoRoot);
2843
2666
  p__namespace.outro(color__default.green("Happy coding! \u2728"));
2844
2667
  process.exit(0);
2845
2668
  }
2846
2669
  }
2847
2670
  async function main() {
2848
- const program = new commander.Command().name("create-krispya").description(
2849
- "CLI for creating Vanilla, React, and React Three Fiber projects"
2850
- ).argument("[name]", "name for the project").option("--type <type>", "project type: app or library (default: app)").option(
2671
+ const program = new commander.Command().name("create-krispya").description("CLI for creating Vanilla, React, and React Three Fiber projects").argument("[name]", "name for the project").option("--type <type>", "project type: app or library (default: app)").option(
2851
2672
  "--bundler <bundler>",
2852
2673
  "library bundler: unbuild or tsdown (default: unbuild, only for libraries)"
2853
2674
  ).option(
2854
2675
  "--template <type>",
2855
2676
  "project template: vanilla, vanilla-js, react, react-js, r3f, r3f-js (default: vanilla)"
2856
- ).option(
2857
- "--linter <type>",
2858
- "linter: eslint, oxlint, or biome (default: oxlint)"
2859
- ).option(
2860
- "--formatter <type>",
2861
- "formatter: prettier, oxfmt, or biome (default: prettier)"
2862
- ).option("--drei", "add @react-three/drei (r3f only)").option("--handle", "add @react-three/handle (r3f only)").option("--leva", "add leva (r3f only)").option("--postprocessing", "add @react-three/postprocessing (r3f only)").option("--rapier", "add @react-three/rapier (r3f only)").option("--xr", "add @react-three/xr (r3f only)").option("--uikit", "add @react-three/uikit (r3f only)").option("--offscreen", "add @react-three/offscreen (r3f only)").option("--zustand", "add zustand (r3f only)").option("--koota", "add koota (r3f only)").option("--triplex", "set up triplex development environment (r3f only)").option("--viverse", "set up viverse deployment (r3f only)").option(
2863
- "--package-manager <manager>",
2864
- "specify package manager (e.g. npm, yarn, pnpm)"
2865
- ).option(
2677
+ ).option("--linter <type>", "linter: eslint, oxlint, or biome (default: oxlint)").option("--formatter <type>", "formatter: prettier, oxfmt, or biome (default: prettier)").option("--drei", "add @react-three/drei (r3f only)").option("--handle", "add @react-three/handle (r3f only)").option("--leva", "add leva (r3f only)").option("--postprocessing", "add @react-three/postprocessing (r3f only)").option("--rapier", "add @react-three/rapier (r3f only)").option("--xr", "add @react-three/xr (r3f only)").option("--uikit", "add @react-three/uikit (r3f only)").option("--offscreen", "add @react-three/offscreen (r3f only)").option("--zustand", "add zustand (r3f only)").option("--koota", "add koota (r3f only)").option("--triplex", "set up triplex development environment (r3f only)").option("--viverse", "set up viverse deployment (r3f only)").option("--package-manager <manager>", "specify package manager (e.g. npm, yarn, pnpm)").option(
2866
2678
  "--pnpm-manage-versions",
2867
2679
  "enable manage-package-manager-versions in pnpm-workspace.yaml (default: true)"
2868
2680
  ).option(
@@ -2871,16 +2683,7 @@ async function main() {
2871
2683
  ).option(
2872
2684
  "--node-version <version>",
2873
2685
  'set Node.js version for engines.node field (default: "latest")'
2874
- ).option(
2875
- "--workspace",
2876
- "Add package to current monorepo workspace (non-interactive)"
2877
- ).option(
2878
- "--dir <directory>",
2879
- "Target directory for --workspace (default: apps/ or packages/)"
2880
- ).option("--clear-config", "Clear saved preferences (e.g. editor choice)").option("--config-path", "Print the path to the config file").option(
2881
- "--check",
2882
- "Check if current directory is in a valid monorepo workspace"
2883
- ).option("--fix", "Fix monorepo by generating missing .config packages").option("--update", "Update monorepo workspace to latest configuration").option("-y, --yes", "Non-interactive mode - accept all prompts").option(
2686
+ ).option("--workspace", "Add package to current monorepo workspace (non-interactive)").option("--dir <directory>", "Target directory for --workspace (default: apps/ or packages/)").option("--clear-config", "Clear saved preferences (e.g. editor choice)").option("--config-path", "Print the path to the config file").option("--check", "Check if current directory is in a valid monorepo workspace").option("--fix", "Fix monorepo by generating missing .config packages").option("--update", "Update monorepo workspace to latest configuration").option("-y, --yes", "Non-interactive mode - accept all prompts").option(
2884
2687
  "--path <directory>",
2885
2688
  "Run in specified directory instead of current working directory"
2886
2689
  ).action(async (name, options) => {
@@ -2942,9 +2745,7 @@ async function main() {
2942
2745
  if (options.dir && !options.workspace) {
2943
2746
  console.error(color__default.red("Error:") + " --dir requires --workspace flag");
2944
2747
  console.log(
2945
- color__default.dim(
2946
- " Example: pnpm create krispya my-lib --workspace --dir examples"
2947
- )
2748
+ color__default.dim(" Example: pnpm create krispya my-lib --workspace --dir examples")
2948
2749
  );
2949
2750
  process.exit(1);
2950
2751
  }
@@ -2984,9 +2785,9 @@ async function main() {
2984
2785
  viverse: options.viverse ? {} : void 0,
2985
2786
  triplex: options.triplex ? {} : void 0
2986
2787
  },
2987
- packageManager: options.packageManager,
2788
+ packageManager: options.packageManager ? { name: options.packageManager } : void 0,
2988
2789
  pnpmManageVersions: options.pnpmManageVersions,
2989
- nodeVersion: options.nodeVersion ?? "latest"
2790
+ engine: { name: "node", version: options.nodeVersion ?? "latest" }
2990
2791
  };
2991
2792
  } else {
2992
2793
  const presets = hasConfigOptions(options) ? {
@@ -2996,7 +2797,7 @@ async function main() {
2996
2797
  linter: options.linter,
2997
2798
  formatter: options.formatter,
2998
2799
  packageManager: options.packageManager,
2999
- nodeVersion: options.nodeVersion,
2800
+ engine: options.nodeVersion ? { name: "node", version: options.nodeVersion } : void 0,
3000
2801
  pnpmManageVersions: options.pnpmManageVersions,
3001
2802
  drei: options.drei,
3002
2803
  handle: options.handle,