create-krispya 0.16.0 → 0.17.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.
@@ -270,6 +270,7 @@ async function detectTooling(root) {
270
270
 
271
271
  const DEFAULT_MINIMUM_RELEASE_AGE_MINUTES = 1440;
272
272
  const MINUTE_IN_MS = 60 * 1e3;
273
+ const SEMVER_PATTERN = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
273
274
  function getMinimumReleaseAgeMinutes(options) {
274
275
  return Math.max(0, options?.minimumReleaseAgeMinutes ?? DEFAULT_MINIMUM_RELEASE_AGE_MINUTES);
275
276
  }
@@ -285,6 +286,62 @@ function isVersionOldEnough(version, time, options) {
285
286
  function getInstallableVersions(versions, time, options) {
286
287
  return [...versions].filter((version) => isVersionOldEnough(version, time, options));
287
288
  }
289
+ function parseSemver(version) {
290
+ const match = version.match(SEMVER_PATTERN);
291
+ if (match == null) return void 0;
292
+ return {
293
+ major: Number.parseInt(match[1], 10),
294
+ minor: Number.parseInt(match[2], 10),
295
+ patch: Number.parseInt(match[3], 10),
296
+ prerelease: match[4]?.split(".") ?? []
297
+ };
298
+ }
299
+ function hasPrerelease(version) {
300
+ return (parseSemver(version)?.prerelease.length ?? 0) > 0;
301
+ }
302
+ function comparePrerelease(aParts, bParts) {
303
+ if (aParts.length === 0 && bParts.length === 0) return 0;
304
+ if (aParts.length === 0) return 1;
305
+ if (bParts.length === 0) return -1;
306
+ const maxLength = Math.max(aParts.length, bParts.length);
307
+ for (let index = 0; index < maxLength; index += 1) {
308
+ const aPart = aParts[index];
309
+ const bPart = bParts[index];
310
+ if (aPart == null) return -1;
311
+ if (bPart == null) return 1;
312
+ if (aPart === bPart) continue;
313
+ const aNumber = /^\d+$/.test(aPart) ? Number.parseInt(aPart, 10) : void 0;
314
+ const bNumber = /^\d+$/.test(bPart) ? Number.parseInt(bPart, 10) : void 0;
315
+ if (aNumber != null && bNumber != null) return aNumber - bNumber;
316
+ if (aNumber != null) return -1;
317
+ if (bNumber != null) return 1;
318
+ return aPart.localeCompare(bPart);
319
+ }
320
+ return 0;
321
+ }
322
+ function compareSemver(a, b) {
323
+ const aParsed = parseSemver(a);
324
+ const bParsed = parseSemver(b);
325
+ if (aParsed == null || bParsed == null) {
326
+ return compareNumericSemver(a, b);
327
+ }
328
+ const majorDifference = aParsed.major - bParsed.major;
329
+ if (majorDifference !== 0) return majorDifference;
330
+ const minorDifference = aParsed.minor - bParsed.minor;
331
+ if (minorDifference !== 0) return minorDifference;
332
+ const patchDifference = aParsed.patch - bParsed.patch;
333
+ if (patchDifference !== 0) return patchDifference;
334
+ return comparePrerelease(aParsed.prerelease, bParsed.prerelease);
335
+ }
336
+ function getLatestChannelVersions(versions, latestVersion) {
337
+ const availableVersions = [...versions];
338
+ if (latestVersion == null) return availableVersions.filter((version) => !hasPrerelease(version));
339
+ const latestIsPrerelease = hasPrerelease(latestVersion);
340
+ return availableVersions.filter((version) => {
341
+ if (!latestIsPrerelease && hasPrerelease(version)) return false;
342
+ return compareSemver(version, latestVersion) <= 0;
343
+ });
344
+ }
288
345
  async function fetchNpmPackageMetadata(packageName) {
289
346
  const response = await fetch(`https://registry.npmjs.org/${packageName}`);
290
347
  return await response.json();
@@ -302,10 +359,10 @@ async function getLatestNpmVersion(packageName, fallback, options) {
302
359
  return latestVersion;
303
360
  }
304
361
  const latestInstallableVersion = getInstallableVersions(
305
- Object.keys(data.versions ?? {}),
362
+ getLatestChannelVersions(Object.keys(data.versions ?? {}), latestVersion),
306
363
  data.time,
307
364
  options
308
- ).sort((a, b) => compareNumericSemver(b, a))[0];
365
+ ).sort((a, b) => compareSemver(b, a))[0];
309
366
  return latestInstallableVersion ?? fallback;
310
367
  } catch {
311
368
  return fallback;
@@ -332,7 +389,7 @@ function compareNumericSemver(a, b) {
332
389
  return 0;
333
390
  }
334
391
  function getLatestMatchingMajorVersion(versions, majorVersion, time, options) {
335
- return getInstallableVersions(versions, time, options).filter((version) => version.split(".")[0] === majorVersion).sort((a, b) => compareNumericSemver(b, a))[0];
392
+ return getInstallableVersions(versions, time, options).filter((version) => version.split(".")[0] === majorVersion).filter((version) => !hasPrerelease(version)).sort((a, b) => compareSemver(b, a))[0];
336
393
  }
337
394
  async function getLatestNpmMajorVersion(packageName, majorVersion, fallback, options) {
338
395
  try {
@@ -610,6 +667,8 @@ function getConfigPath() {
610
667
  }
611
668
 
612
669
  const ALL_AI_PLATFORMS = ["agents", "claude"];
670
+ const AI_FILE_MANAGED_BEGIN = "<!-- managed:start -->";
671
+ const AI_FILE_MANAGED_END = "<!-- managed:end -->";
613
672
  const AI_PLATFORM_LABELS = {
614
673
  agents: "AGENTS.md",
615
674
  claude: "CLAUDE.md"
@@ -621,12 +680,14 @@ const AI_PLATFORM_HINTS = {
621
680
  function renderAiFiles(files, params) {
622
681
  const { platforms, isMonorepo, configStrategy, hasTypecheck, ...rest } = params;
623
682
  if (platforms.length === 0) return;
624
- const content = generateWorkspace({
625
- ...rest,
626
- isMonorepo: !!isMonorepo,
627
- configStrategy: configStrategy ?? "stealth",
628
- hasTypecheck: hasTypecheck ?? false
629
- });
683
+ const content = renderManagedAiFileContent(
684
+ generateWorkspace({
685
+ ...rest,
686
+ isMonorepo: !!isMonorepo,
687
+ configStrategy: configStrategy ?? "stealth",
688
+ hasTypecheck: hasTypecheck ?? false
689
+ })
690
+ );
630
691
  const pointer = "See [`AGENTS.md`](./Agents.md) for agent context.\n";
631
692
  const hasAgents = platforms.includes("agents");
632
693
  const hasClaude = platforms.includes("claude");
@@ -640,18 +701,89 @@ function renderAiFiles(files, params) {
640
701
  }
641
702
  }
642
703
  }
704
+ function renderManagedAiFileContent(content) {
705
+ return [AI_FILE_MANAGED_BEGIN, content.trimEnd(), AI_FILE_MANAGED_END, ""].join("\n");
706
+ }
707
+ function getManagedBlockRange$1(content) {
708
+ const beginIndex = content.indexOf(AI_FILE_MANAGED_BEGIN);
709
+ const endIndex = content.indexOf(AI_FILE_MANAGED_END);
710
+ if (beginIndex === -1 && endIndex === -1) {
711
+ return { status: "missing" };
712
+ }
713
+ if (beginIndex === -1 || endIndex === -1 || endIndex < beginIndex) {
714
+ return { status: "conflicted" };
715
+ }
716
+ return {
717
+ status: "found",
718
+ beginIndex,
719
+ endIndex: endIndex + AI_FILE_MANAGED_END.length
720
+ };
721
+ }
722
+ function getManagedInnerContent(content) {
723
+ const range = getManagedBlockRange$1(content);
724
+ if (range.status !== "found") return void 0;
725
+ return content.slice(
726
+ range.beginIndex + AI_FILE_MANAGED_BEGIN.length,
727
+ range.endIndex - AI_FILE_MANAGED_END.length
728
+ ).replace(/^\r?\n/, "").replace(/\r?\n$/, "");
729
+ }
730
+ function mergeMissingManagedAiBlock(currentContent, expectedContent, legacyContent) {
731
+ if (currentContent.trim() === "") return expectedContent;
732
+ if (legacyContent != null && currentContent.startsWith(legacyContent)) {
733
+ const suffix = currentContent.slice(legacyContent.length);
734
+ return suffix === "" ? expectedContent : `${expectedContent.trimEnd()}${suffix}`;
735
+ }
736
+ return `${expectedContent.trimEnd()}
737
+
738
+ ${currentContent.trim()}
739
+ `;
740
+ }
741
+ function isManagedAiFilePath(path) {
742
+ return path === "AGENTS.md" || path === "CLAUDE.md";
743
+ }
744
+ function mergeAiFileContent(currentContent, expectedContent) {
745
+ if (!expectedContent.includes(AI_FILE_MANAGED_BEGIN)) {
746
+ return {
747
+ content: expectedContent,
748
+ mergeSafe: false
749
+ };
750
+ }
751
+ const range = getManagedBlockRange$1(currentContent);
752
+ if (range.status === "found") {
753
+ return {
754
+ content: `${currentContent.slice(0, range.beginIndex)}${expectedContent.trimEnd()}${currentContent.slice(
755
+ range.endIndex
756
+ )}`,
757
+ mergeSafe: true
758
+ };
759
+ }
760
+ if (range.status === "conflicted") {
761
+ return {
762
+ content: expectedContent,
763
+ mergeSafe: false
764
+ };
765
+ }
766
+ return {
767
+ content: mergeMissingManagedAiBlock(
768
+ currentContent,
769
+ expectedContent,
770
+ getManagedInnerContent(expectedContent)
771
+ ),
772
+ mergeSafe: true
773
+ };
774
+ }
643
775
  function generateWorkspace(ctx) {
644
776
  const { packageManager, linter, formatter, hasTypecheck } = ctx;
645
777
  const exampleFiles = "src/App.tsx src/core/systems/move-entity.ts";
646
778
  const commands = getAfterEditingCommands(ctx, exampleFiles);
647
779
  const sections = [
648
- "# Workspace Tools",
780
+ "## Workspace Tools",
649
781
  "",
650
782
  `- **Package Manager:** ${packageManager}`,
651
783
  `- **Linter:** ${linter}`,
652
784
  `- **Formatter:** ${formatter}`,
653
785
  "",
654
- "## After Editing",
786
+ "### After Editing",
655
787
  ""
656
788
  ];
657
789
  if (hasTypecheck) {
@@ -1107,6 +1239,54 @@ function isEnabledOption(option) {
1107
1239
  return option != null && option !== false;
1108
1240
  }
1109
1241
 
1242
+ function renderJson(value, options = {}) {
1243
+ const json = JSON.stringify(value, null, 2);
1244
+ const content = options.inlineArrays === false ? json : inlinePrimitiveArrays(json, options);
1245
+ return `${content}
1246
+ `;
1247
+ }
1248
+ function inlinePrimitiveArrays(json, options) {
1249
+ const printWidth = options.printWidth ?? 102;
1250
+ const lines = json.split("\n");
1251
+ const output = [];
1252
+ for (let index = 0; index < lines.length; index++) {
1253
+ const line = lines[index];
1254
+ const openIndex = line.indexOf("[");
1255
+ if (openIndex === -1 || line.slice(openIndex).trim() !== "[") {
1256
+ output.push(line);
1257
+ continue;
1258
+ }
1259
+ const items = [];
1260
+ let cursor = index + 1;
1261
+ let closingComma = "";
1262
+ for (; cursor < lines.length; cursor++) {
1263
+ const item = lines[cursor].trim();
1264
+ const closingMatch = item.match(/^\](,?)$/);
1265
+ if (closingMatch) {
1266
+ closingComma = closingMatch[1] ?? "";
1267
+ break;
1268
+ }
1269
+ if (!/^(?:"(?:[^"\\]|\\.)*"|-?\d+(?:\.\d+)?|true|false|null),?$/.test(item)) {
1270
+ items.length = 0;
1271
+ break;
1272
+ }
1273
+ items.push(item.replace(/,$/, ""));
1274
+ }
1275
+ if (items.length === 0 || cursor >= lines.length) {
1276
+ output.push(line);
1277
+ continue;
1278
+ }
1279
+ const nextLine = `${line.slice(0, openIndex)}[${items.join(", ")}]${closingComma}`;
1280
+ if (nextLine.length > printWidth) {
1281
+ output.push(line);
1282
+ continue;
1283
+ }
1284
+ output.push(nextLine);
1285
+ index = cursor;
1286
+ }
1287
+ return output.join("\n");
1288
+ }
1289
+
1110
1290
  function renderTypescriptConfig(baseTemplateOrParams) {
1111
1291
  const params = typeof baseTemplateOrParams === "string" ? { baseTemplate: baseTemplateOrParams } : baseTemplateOrParams;
1112
1292
  const {
@@ -1138,15 +1318,11 @@ function renderTypescriptConfig(baseTemplateOrParams) {
1138
1318
  const baseConfig = isReact || isR3f ? "@config/typescript/react.json" : "@config/typescript/app.json";
1139
1319
  files["tsconfig.json"] = {
1140
1320
  type: "text",
1141
- content: JSON.stringify(
1142
- {
1143
- $schema: "https://json.schemastore.org/tsconfig",
1144
- extends: baseConfig,
1145
- include: ["src/**/*", "tests/**/*"]
1146
- },
1147
- null,
1148
- 2
1149
- )
1321
+ content: renderJson({
1322
+ $schema: "https://json.schemastore.org/tsconfig",
1323
+ extends: baseConfig,
1324
+ include: ["src/**/*", "tests/**/*"]
1325
+ })
1150
1326
  };
1151
1327
  return { files, devDependencies };
1152
1328
  }
@@ -1158,7 +1334,7 @@ function renderTypescriptConfig(baseTemplateOrParams) {
1158
1334
  };
1159
1335
  files["tsconfig.json"] = {
1160
1336
  type: "text",
1161
- content: JSON.stringify(tsConfig, null, 2)
1337
+ content: renderJson(tsConfig)
1162
1338
  };
1163
1339
  const tsConfigApp = {
1164
1340
  $schema: "https://json.schemastore.org/tsconfig",
@@ -1181,7 +1357,7 @@ function renderTypescriptConfig(baseTemplateOrParams) {
1181
1357
  };
1182
1358
  files[".config/tsconfig.app.json"] = {
1183
1359
  type: "text",
1184
- content: JSON.stringify(tsConfigApp, null, 2)
1360
+ content: renderJson(tsConfigApp)
1185
1361
  };
1186
1362
  const tsConfigNode = {
1187
1363
  $schema: "https://json.schemastore.org/tsconfig",
@@ -1203,7 +1379,7 @@ function renderTypescriptConfig(baseTemplateOrParams) {
1203
1379
  };
1204
1380
  files[".config/tsconfig.node.json"] = {
1205
1381
  type: "text",
1206
- content: JSON.stringify(tsConfigNode, null, 2)
1382
+ content: renderJson(tsConfigNode)
1207
1383
  };
1208
1384
  } else {
1209
1385
  const tsConfig = {
@@ -1213,7 +1389,7 @@ function renderTypescriptConfig(baseTemplateOrParams) {
1213
1389
  };
1214
1390
  files["tsconfig.json"] = {
1215
1391
  type: "text",
1216
- content: JSON.stringify(tsConfig, null, 2)
1392
+ content: renderJson(tsConfig)
1217
1393
  };
1218
1394
  const tsConfigApp = {
1219
1395
  $schema: "https://json.schemastore.org/tsconfig",
@@ -1236,7 +1412,7 @@ function renderTypescriptConfig(baseTemplateOrParams) {
1236
1412
  };
1237
1413
  files["tsconfig.app.json"] = {
1238
1414
  type: "text",
1239
- content: JSON.stringify(tsConfigApp, null, 2)
1415
+ content: renderJson(tsConfigApp)
1240
1416
  };
1241
1417
  const tsConfigNode = {
1242
1418
  $schema: "https://json.schemastore.org/tsconfig",
@@ -1258,7 +1434,7 @@ function renderTypescriptConfig(baseTemplateOrParams) {
1258
1434
  };
1259
1435
  files["tsconfig.node.json"] = {
1260
1436
  type: "text",
1261
- content: JSON.stringify(tsConfigNode, null, 2)
1437
+ content: renderJson(tsConfigNode)
1262
1438
  };
1263
1439
  }
1264
1440
  return { files, devDependencies };
@@ -1446,7 +1622,7 @@ function renderPackageJson(params) {
1446
1622
  }
1447
1623
  files["package.json"] = {
1448
1624
  type: "text",
1449
- content: JSON.stringify(packageJson, null, 2)
1625
+ content: renderJson(packageJson, { inlineArrays: false })
1450
1626
  };
1451
1627
  if (isPnpm && !options.workspaceRoot) {
1452
1628
  files["pnpm-workspace.yaml"] = {
@@ -1818,6 +1994,8 @@ function renderTestFiles(params) {
1818
1994
  return files;
1819
1995
  }
1820
1996
 
1997
+ const GITIGNORE_MANAGED_BEGIN = "# managed:start";
1998
+ const GITIGNORE_MANAGED_END = "# managed:end";
1821
1999
  const COMMON_GITIGNORE_LINES = [
1822
2000
  "node_modules",
1823
2001
  "dist",
@@ -1827,13 +2005,77 @@ const COMMON_GITIGNORE_LINES = [
1827
2005
  "!.env.example",
1828
2006
  ".pnpm-store"
1829
2007
  ];
2008
+ function getCoreGitignoreLines(variant) {
2009
+ return variant === "workspace-root" ? [...COMMON_GITIGNORE_LINES, ".DS_Store"] : COMMON_GITIGNORE_LINES;
2010
+ }
2011
+ function renderManagedGitignoreBlock(variant) {
2012
+ return [GITIGNORE_MANAGED_BEGIN, ...getCoreGitignoreLines(variant), GITIGNORE_MANAGED_END].join(
2013
+ "\n"
2014
+ );
2015
+ }
1830
2016
  function renderGitignore(variant) {
1831
- const lines = variant === "workspace-root" ? [...COMMON_GITIGNORE_LINES, ".DS_Store"] : COMMON_GITIGNORE_LINES;
1832
2017
  return {
1833
2018
  type: "text",
1834
- content: lines.join("\n")
2019
+ content: renderManagedGitignoreBlock(variant)
1835
2020
  };
1836
2021
  }
2022
+ function getManagedBlockRange(content) {
2023
+ const beginIndex = content.indexOf(GITIGNORE_MANAGED_BEGIN);
2024
+ const endIndex = content.indexOf(GITIGNORE_MANAGED_END);
2025
+ if (beginIndex === -1 && endIndex === -1) {
2026
+ return { status: "missing" };
2027
+ }
2028
+ if (beginIndex === -1 || endIndex === -1 || endIndex < beginIndex) {
2029
+ return { status: "conflicted" };
2030
+ }
2031
+ return {
2032
+ status: "found",
2033
+ beginIndex,
2034
+ endIndex: endIndex + GITIGNORE_MANAGED_END.length
2035
+ };
2036
+ }
2037
+ function trimBlankEdges(lines) {
2038
+ let start = 0;
2039
+ let end = lines.length;
2040
+ while (start < end && lines[start]?.trim() === "") {
2041
+ start++;
2042
+ }
2043
+ while (end > start && lines[end - 1]?.trim() === "") {
2044
+ end--;
2045
+ }
2046
+ return lines.slice(start, end);
2047
+ }
2048
+ function mergeGitignoreContent(currentContent, variant) {
2049
+ const managedBlock = renderManagedGitignoreBlock(variant);
2050
+ const range = getManagedBlockRange(currentContent);
2051
+ if (range.status === "found") {
2052
+ return {
2053
+ content: `${currentContent.slice(0, range.beginIndex)}${managedBlock}${currentContent.slice(
2054
+ range.endIndex
2055
+ )}`,
2056
+ mergeSafe: true
2057
+ };
2058
+ }
2059
+ if (range.status === "conflicted") {
2060
+ return {
2061
+ content: managedBlock,
2062
+ mergeSafe: false
2063
+ };
2064
+ }
2065
+ const coreLines = new Set(getCoreGitignoreLines(variant));
2066
+ const customLines = trimBlankEdges(
2067
+ currentContent.split(/\r?\n/).filter((line) => !coreLines.has(line.trim()))
2068
+ );
2069
+ return {
2070
+ content: customLines.length > 0 ? `${managedBlock}
2071
+
2072
+ ${customLines.join("\n")}` : managedBlock,
2073
+ mergeSafe: true
2074
+ };
2075
+ }
2076
+ function detectGitignoreVariant(content) {
2077
+ return content.split(/\r?\n/).includes(".DS_Store") ? "workspace-root" : "standalone";
2078
+ }
1837
2079
 
1838
2080
  const defaultFormatterMetaConfig = {
1839
2081
  printWidth: 102,
@@ -2006,13 +2248,9 @@ function renderVscodeFiles$1(params) {
2006
2248
  const uniqueRecommendations = [...new Set(recommendations)];
2007
2249
  files[".vscode/extensions.json"] = {
2008
2250
  type: "text",
2009
- content: JSON.stringify(
2010
- {
2011
- recommendations: uniqueRecommendations
2012
- },
2013
- null,
2014
- 2
2015
- )
2251
+ content: renderJson({
2252
+ recommendations: uniqueRecommendations
2253
+ })
2016
2254
  };
2017
2255
  }
2018
2256
  const resolvedSettings = {
@@ -2025,7 +2263,7 @@ function renderVscodeFiles$1(params) {
2025
2263
  );
2026
2264
  files[".vscode/settings.json"] = {
2027
2265
  type: "text",
2028
- content: JSON.stringify(sortedSettings, null, 2)
2266
+ content: renderJson(sortedSettings)
2029
2267
  };
2030
2268
  }
2031
2269
  return files;
@@ -2200,15 +2438,14 @@ function renderTypescriptConfigPackage(files) {
2200
2438
  const basePath = ".config/typescript";
2201
2439
  files[`${basePath}/package.json`] = {
2202
2440
  type: "text",
2203
- content: JSON.stringify(
2441
+ content: renderJson(
2204
2442
  {
2205
2443
  name: "@config/typescript",
2206
2444
  version: "0.1.0",
2207
2445
  private: true,
2208
2446
  files: ["base.json", "app.json", "node.json", "react.json"]
2209
2447
  },
2210
- null,
2211
- 2
2448
+ { inlineArrays: false }
2212
2449
  )
2213
2450
  };
2214
2451
  files[`${basePath}/README.md`] = {
@@ -2238,82 +2475,65 @@ In your package's \`tsconfig.json\`:
2238
2475
  };
2239
2476
  files[`${basePath}/base.json`] = {
2240
2477
  type: "text",
2241
- content: JSON.stringify(
2242
- {
2243
- $schema: "https://json.schemastore.org/tsconfig",
2244
- compilerOptions: {
2245
- target: "ESNext",
2246
- module: "ESNext",
2247
- moduleResolution: "bundler",
2248
- esModuleInterop: true,
2249
- allowSyntheticDefaultImports: true,
2250
- strict: true,
2251
- skipLibCheck: true,
2252
- composite: true,
2253
- rewriteRelativeImportExtensions: true,
2254
- erasableSyntaxOnly: true
2255
- }
2256
- },
2257
- null,
2258
- 2
2259
- )
2478
+ content: renderJson({
2479
+ $schema: "https://json.schemastore.org/tsconfig",
2480
+ compilerOptions: {
2481
+ target: "ESNext",
2482
+ module: "ESNext",
2483
+ moduleResolution: "bundler",
2484
+ esModuleInterop: true,
2485
+ allowSyntheticDefaultImports: true,
2486
+ strict: true,
2487
+ skipLibCheck: true,
2488
+ composite: true,
2489
+ rewriteRelativeImportExtensions: true,
2490
+ erasableSyntaxOnly: true
2491
+ }
2492
+ })
2260
2493
  };
2261
2494
  files[`${basePath}/app.json`] = {
2262
2495
  type: "text",
2263
- content: JSON.stringify(
2264
- {
2265
- $schema: "https://json.schemastore.org/tsconfig",
2266
- extends: "./base.json",
2267
- compilerOptions: {
2268
- lib: ["DOM", "DOM.Iterable", "ESNext"]
2269
- }
2270
- },
2271
- null,
2272
- 2
2273
- )
2496
+ content: renderJson({
2497
+ $schema: "https://json.schemastore.org/tsconfig",
2498
+ extends: "./base.json",
2499
+ compilerOptions: {
2500
+ lib: ["DOM", "DOM.Iterable", "ESNext"]
2501
+ }
2502
+ })
2274
2503
  };
2275
2504
  files[`${basePath}/node.json`] = {
2276
2505
  type: "text",
2277
- content: JSON.stringify(
2278
- {
2279
- $schema: "https://json.schemastore.org/tsconfig",
2280
- extends: "./base.json",
2281
- compilerOptions: {
2282
- lib: ["ESNext"]
2283
- }
2284
- },
2285
- null,
2286
- 2
2287
- )
2506
+ content: renderJson({
2507
+ $schema: "https://json.schemastore.org/tsconfig",
2508
+ extends: "./base.json",
2509
+ compilerOptions: {
2510
+ lib: ["ESNext"]
2511
+ }
2512
+ })
2288
2513
  };
2289
2514
  files[`${basePath}/react.json`] = {
2290
2515
  type: "text",
2291
- content: JSON.stringify(
2292
- {
2293
- $schema: "https://json.schemastore.org/tsconfig",
2294
- extends: "./app.json",
2295
- compilerOptions: {
2296
- jsx: "react-jsx"
2297
- }
2298
- },
2299
- null,
2300
- 2
2301
- )
2516
+ content: renderJson({
2517
+ $schema: "https://json.schemastore.org/tsconfig",
2518
+ extends: "./app.json",
2519
+ compilerOptions: {
2520
+ jsx: "react-jsx"
2521
+ }
2522
+ })
2302
2523
  };
2303
2524
  }
2304
2525
  function renderOxlintConfigPackage(files) {
2305
2526
  const basePath = ".config/oxlint";
2306
2527
  files[`${basePath}/package.json`] = {
2307
2528
  type: "text",
2308
- content: JSON.stringify(
2529
+ content: renderJson(
2309
2530
  {
2310
2531
  name: "@config/oxlint",
2311
2532
  version: "0.1.0",
2312
2533
  private: true,
2313
2534
  files: ["base.json", "react.json"]
2314
2535
  },
2315
- null,
2316
- 2
2536
+ { inlineArrays: false }
2317
2537
  )
2318
2538
  };
2319
2539
  files[`${basePath}/README.md`] = {
@@ -2338,25 +2558,21 @@ oxlint -c node_modules/@config/oxlint/base.json
2338
2558
  };
2339
2559
  files[`${basePath}/base.json`] = {
2340
2560
  type: "text",
2341
- content: JSON.stringify(
2561
+ content: renderJson(
2342
2562
  renderOxlintConfig({
2343
2563
  schemaPath: "./node_modules/oxlint/configuration_schema.json",
2344
2564
  typescript: true
2345
- }),
2346
- null,
2347
- 2
2565
+ })
2348
2566
  )
2349
2567
  };
2350
2568
  files[`${basePath}/react.json`] = {
2351
2569
  type: "text",
2352
- content: JSON.stringify(
2570
+ content: renderJson(
2353
2571
  renderOxlintConfig({
2354
2572
  schemaPath: "./node_modules/oxlint/configuration_schema.json",
2355
2573
  react: true,
2356
2574
  typescript: true
2357
- }),
2358
- null,
2359
- 2
2575
+ })
2360
2576
  )
2361
2577
  };
2362
2578
  }
@@ -2364,7 +2580,7 @@ function renderEslintConfigPackage(files) {
2364
2580
  const basePath = ".config/eslint";
2365
2581
  files[`${basePath}/package.json`] = {
2366
2582
  type: "text",
2367
- content: JSON.stringify(
2583
+ content: renderJson(
2368
2584
  {
2369
2585
  name: "@config/eslint",
2370
2586
  version: "0.1.0",
@@ -2380,8 +2596,7 @@ function renderEslintConfigPackage(files) {
2380
2596
  "typescript-eslint": "^8.18.0"
2381
2597
  }
2382
2598
  },
2383
- null,
2384
- 2
2599
+ { inlineArrays: false }
2385
2600
  )
2386
2601
  };
2387
2602
  files[`${basePath}/README.md`] = {
@@ -2416,52 +2631,52 @@ export default [...react];
2416
2631
  };
2417
2632
  files[`${basePath}/base.js`] = {
2418
2633
  type: "text",
2419
- content: `import js from "@eslint/js";
2420
- import tseslint from "typescript-eslint";
2634
+ content: `import js from '@eslint/js';
2635
+ import tseslint from 'typescript-eslint';
2421
2636
 
2422
2637
  export default tseslint.config(
2423
2638
  js.configs.recommended,
2424
2639
  ...tseslint.configs.recommended,
2425
2640
  {
2426
2641
  rules: {
2427
- "@typescript-eslint/no-unused-vars": [
2428
- "error",
2642
+ '@typescript-eslint/no-unused-vars': [
2643
+ 'error',
2429
2644
  {
2430
- argsIgnorePattern: "^_",
2431
- varsIgnorePattern: "^_",
2432
- caughtErrorsIgnorePattern: "^_",
2645
+ argsIgnorePattern: '^_',
2646
+ varsIgnorePattern: '^_',
2647
+ caughtErrorsIgnorePattern: '^_',
2433
2648
  },
2434
2649
  ],
2435
2650
  },
2436
2651
  },
2437
2652
  {
2438
- ignores: ["dist/**", "node_modules/**"],
2653
+ ignores: ['dist/**', 'node_modules/**'],
2439
2654
  }
2440
2655
  );
2441
2656
  `
2442
2657
  };
2443
2658
  files[`${basePath}/react.js`] = {
2444
2659
  type: "text",
2445
- content: `import js from "@eslint/js";
2446
- import tseslint from "typescript-eslint";
2660
+ content: `import js from '@eslint/js';
2661
+ import tseslint from 'typescript-eslint';
2447
2662
 
2448
2663
  export default tseslint.config(
2449
2664
  js.configs.recommended,
2450
2665
  ...tseslint.configs.recommended,
2451
2666
  {
2452
2667
  rules: {
2453
- "@typescript-eslint/no-unused-vars": [
2454
- "error",
2668
+ '@typescript-eslint/no-unused-vars': [
2669
+ 'error',
2455
2670
  {
2456
- argsIgnorePattern: "^_",
2457
- varsIgnorePattern: "^_",
2458
- caughtErrorsIgnorePattern: "^_",
2671
+ argsIgnorePattern: '^_',
2672
+ varsIgnorePattern: '^_',
2673
+ caughtErrorsIgnorePattern: '^_',
2459
2674
  },
2460
2675
  ],
2461
2676
  },
2462
2677
  },
2463
2678
  {
2464
- ignores: ["dist/**", "node_modules/**"],
2679
+ ignores: ['dist/**', 'node_modules/**'],
2465
2680
  }
2466
2681
  );
2467
2682
  `
@@ -2471,7 +2686,7 @@ function renderPrettierConfigPackage(files) {
2471
2686
  const basePath = ".config/prettier";
2472
2687
  files[`${basePath}/package.json`] = {
2473
2688
  type: "text",
2474
- content: JSON.stringify(
2689
+ content: renderJson(
2475
2690
  {
2476
2691
  name: "@config/prettier",
2477
2692
  version: "0.1.0",
@@ -2482,8 +2697,7 @@ function renderPrettierConfigPackage(files) {
2482
2697
  },
2483
2698
  files: ["base.json", "prettierignore"]
2484
2699
  },
2485
- null,
2486
- 2
2700
+ { inlineArrays: false }
2487
2701
  )
2488
2702
  };
2489
2703
  files[`${basePath}/README.md`] = {
@@ -2515,7 +2729,7 @@ Or in \`.prettierrc.json\`:
2515
2729
  };
2516
2730
  files[`${basePath}/base.json`] = {
2517
2731
  type: "text",
2518
- content: JSON.stringify(toPrettierConfig(), null, 2)
2732
+ content: renderJson(toPrettierConfig())
2519
2733
  };
2520
2734
  files[`${basePath}/prettierignore`] = {
2521
2735
  type: "text",
@@ -2526,15 +2740,14 @@ function renderOxfmtConfigPackage(files) {
2526
2740
  const basePath = ".config/oxfmt";
2527
2741
  files[`${basePath}/package.json`] = {
2528
2742
  type: "text",
2529
- content: JSON.stringify(
2743
+ content: renderJson(
2530
2744
  {
2531
2745
  name: "@config/oxfmt",
2532
2746
  version: "0.1.0",
2533
2747
  private: true,
2534
2748
  files: ["base.json"]
2535
2749
  },
2536
- null,
2537
- 2
2750
+ { inlineArrays: false }
2538
2751
  )
2539
2752
  };
2540
2753
  files[`${basePath}/README.md`] = {
@@ -2558,7 +2771,7 @@ oxfmt -c node_modules/@config/oxfmt/base.json --write .
2558
2771
  };
2559
2772
  files[`${basePath}/base.json`] = {
2560
2773
  type: "text",
2561
- content: JSON.stringify(toOxfmtConfig(), null, 2)
2774
+ content: renderJson(toOxfmtConfig())
2562
2775
  };
2563
2776
  }
2564
2777
 
@@ -2618,7 +2831,7 @@ function renderMonorepo(params) {
2618
2831
  }
2619
2832
  files["package.json"] = {
2620
2833
  type: "text",
2621
- content: JSON.stringify(rootPackageJson, null, 2)
2834
+ content: renderJson(rootPackageJson, { inlineArrays: false })
2622
2835
  };
2623
2836
  if (isPnpm) {
2624
2837
  files["pnpm-workspace.yaml"] = {
@@ -2688,7 +2901,7 @@ export default [...base];
2688
2901
  };
2689
2902
  files["biome.json"] = {
2690
2903
  type: "text",
2691
- content: JSON.stringify(biomeConfig, null, 2)
2904
+ content: renderJson(biomeConfig)
2692
2905
  };
2693
2906
  }
2694
2907
  if (formatter === "oxfmt") {
@@ -2818,7 +3031,7 @@ function planBiome(builder, options) {
2818
3031
  if (isStealth) {
2819
3032
  builder.addFile(".config/biome.json", {
2820
3033
  type: "text",
2821
- content: JSON.stringify(biomeConfig, null, 2)
3034
+ content: renderJson(biomeConfig)
2822
3035
  });
2823
3036
  if (options.linter) {
2824
3037
  builder.addScripts(packageJsonScripts.lint.biome(".config"));
@@ -2829,7 +3042,7 @@ function planBiome(builder, options) {
2829
3042
  } else {
2830
3043
  builder.addFile("biome.json", {
2831
3044
  type: "text",
2832
- content: JSON.stringify(biomeConfig, null, 2)
3045
+ content: renderJson(biomeConfig)
2833
3046
  });
2834
3047
  if (options.linter) {
2835
3048
  builder.addScripts(packageJsonScripts.lint.biome());
@@ -3106,13 +3319,13 @@ function planOxfmt(builder, options) {
3106
3319
  if (isStealth) {
3107
3320
  builder.addFile(".config/oxfmt.json", {
3108
3321
  type: "text",
3109
- content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
3322
+ content: renderJson(toOxfmtConfig(options.config))
3110
3323
  });
3111
3324
  builder.addScripts(packageJsonScripts.format.oxfmt(".config/oxfmt.json"));
3112
3325
  } else {
3113
3326
  builder.addFile("oxfmt.json", {
3114
3327
  type: "text",
3115
- content: JSON.stringify(toOxfmtConfig(options.config), null, 2)
3328
+ content: renderJson(toOxfmtConfig(options.config))
3116
3329
  });
3117
3330
  builder.addScripts(packageJsonScripts.format.oxfmt("oxfmt.json"));
3118
3331
  }
@@ -3157,13 +3370,13 @@ function planOxlint(builder, options) {
3157
3370
  if (isStealth) {
3158
3371
  builder.addFile(".config/oxlint.json", {
3159
3372
  type: "text",
3160
- content: JSON.stringify(oxlintConfig, null, 2)
3373
+ content: renderJson(oxlintConfig)
3161
3374
  });
3162
3375
  builder.addScripts(packageJsonScripts.lint.oxlint(".config/oxlint.json"));
3163
3376
  } else {
3164
3377
  builder.addFile("oxlint.json", {
3165
3378
  type: "text",
3166
- content: JSON.stringify(oxlintConfig, null, 2)
3379
+ content: renderJson(oxlintConfig)
3167
3380
  });
3168
3381
  builder.addScripts(packageJsonScripts.lint.oxlint());
3169
3382
  }
@@ -3202,7 +3415,7 @@ function planPrettier(builder, options) {
3202
3415
  if (isStealth) {
3203
3416
  builder.addFile(".config/prettier.json", {
3204
3417
  type: "text",
3205
- content: JSON.stringify(toPrettierConfig(options.config), null, 2)
3418
+ content: renderJson(toPrettierConfig(options.config))
3206
3419
  });
3207
3420
  builder.addFile(".config/prettierignore", {
3208
3421
  type: "text",
@@ -3214,7 +3427,7 @@ function planPrettier(builder, options) {
3214
3427
  } else {
3215
3428
  builder.addFile(".prettierrc", {
3216
3429
  type: "text",
3217
- content: JSON.stringify(toPrettierConfig(options.config), null, 2)
3430
+ content: renderJson(toPrettierConfig(options.config))
3218
3431
  });
3219
3432
  builder.addFile(".prettierignore", {
3220
3433
  type: "text",
@@ -4198,4 +4411,4 @@ async function planWorkspace(input) {
4198
4411
  };
4199
4412
  }
4200
4413
 
4201
- export { formatNodeTypesVersion as $, ALL_AI_PLATFORMS as A, renderGitignore as B, toPrettierIgnoreContent as C, mergePackageJsonScripts as D, getPackageManagerProfile as E, renderPnpmWorkspaceConfig as F, renderViteConfig as G, packageJsonScripts as H, resolveDefaultPackageJsonScripts as I, formatResolvedPackageVersion as J, getSemverMajorString as K, formatPackageManager as L, renderOxlintConfig as M, resolvePackageManager as N, getSemverMajor as O, compareNumericSemver as P, getPackageDirectoryName as Q, planProject as R, resolveProjectPlanInput as S, validatePackageName as T, clearConfig as U, getConfigPath as V, resolveWorkspacePlanInput as W, planWorkspace as X, DEFAULT_MINIMUM_RELEASE_AGE_MINUTES as Y, assignResolvedPackageVersion as Z, formatEngine as _, getPackageManagerName as a, getEngineSpec as a0, getLatestNodeVersion as a1, getLatestNpmCliVersion as a2, getLatestNpmMajorVersion as a3, getLatestNpmMajorVersionAtOrBelow as a4, getLatestNpmVersion as a5, getLatestPnpmVersion as a6, getLatestYarnVersion as a7, getPackageFallbackVersion as a8, getPackageManagerSpec as a9, isPackageManagerName as aa, materializeJobs as ab, merge as ac, projectPlanInputToOptions as ad, resolveEngine as ae, resolvePackageManagerProfile as af, resolvePackageVersions as ag, resolveProjectFacts as ah, resolveProjectPackageVersions as ai, resolveWorkspaceFacts as aj, setAiPlatforms as ak, setConfigStrategy as al, unique as am, workspacePlanInputToMonorepoParams as an, getBaseTemplate as b, getLanguageFromTemplate as c, generateRandomName as d, getConfigStrategy as e, getAiPlatforms as f, getEngineName as g, AI_PLATFORM_LABELS as h, AI_PLATFORM_HINTS as i, detectTooling as j, parseEngine as k, parseWorkspaceYamlContent as l, renderOxlintConfigPackage as m, renderEslintConfigPackage as n, renderOxfmtConfigPackage as o, parsePackageManagerSpec as p, renderPrettierConfigPackage as q, renderTypescriptConfigPackage as r, shouldEnableReactCompiler as s, resolveMonorepoRootPackageVersions as t, getResolvedPackageVersion as u, validateWorkspace as v, renderVscodeFiles as w, renderAiFiles as x, renderVscodeFiles$1 as y, renderEditorConfig as z };
4414
+ export { resolveWorkspacePlanInput as $, ALL_AI_PLATFORMS as A, renderEditorConfig as B, renderGitignore as C, toPrettierIgnoreContent as D, mergePackageJsonScripts as E, getPackageManagerProfile as F, renderPnpmWorkspaceConfig as G, renderViteConfig as H, mergeGitignoreContent as I, detectGitignoreVariant as J, isManagedAiFilePath as K, mergeAiFileContent as L, packageJsonScripts as M, resolveDefaultPackageJsonScripts as N, formatResolvedPackageVersion as O, getSemverMajorString as P, formatPackageManager as Q, renderOxlintConfig as R, resolvePackageManager as S, getSemverMajor as T, compareNumericSemver as U, getPackageDirectoryName as V, planProject as W, resolveProjectPlanInput as X, validatePackageName as Y, clearConfig as Z, getConfigPath as _, getPackageManagerName as a, planWorkspace as a0, DEFAULT_MINIMUM_RELEASE_AGE_MINUTES as a1, assignResolvedPackageVersion as a2, formatEngine as a3, formatNodeTypesVersion as a4, getEngineSpec as a5, getLatestNodeVersion as a6, getLatestNpmCliVersion as a7, getLatestNpmMajorVersion as a8, getLatestNpmMajorVersionAtOrBelow as a9, getLatestNpmVersion as aa, getLatestPnpmVersion as ab, getLatestYarnVersion as ac, getPackageFallbackVersion as ad, getPackageManagerSpec as ae, isPackageManagerName as af, materializeJobs as ag, merge as ah, projectPlanInputToOptions as ai, resolveEngine as aj, resolvePackageManagerProfile as ak, resolvePackageVersions as al, resolveProjectFacts as am, resolveProjectPackageVersions as an, resolveWorkspaceFacts as ao, setAiPlatforms as ap, setConfigStrategy as aq, unique as ar, workspacePlanInputToMonorepoParams as as, getBaseTemplate as b, getLanguageFromTemplate as c, generateRandomName as d, getConfigStrategy as e, getAiPlatforms as f, getEngineName as g, AI_PLATFORM_LABELS as h, AI_PLATFORM_HINTS as i, detectTooling as j, parseEngine as k, parseWorkspaceYamlContent as l, renderOxlintConfigPackage as m, renderEslintConfigPackage as n, renderOxfmtConfigPackage as o, parsePackageManagerSpec as p, renderPrettierConfigPackage as q, renderTypescriptConfigPackage as r, shouldEnableReactCompiler as s, resolveMonorepoRootPackageVersions as t, getResolvedPackageVersion as u, validateWorkspace as v, renderJson as w, renderVscodeFiles as x, renderAiFiles as y, renderVscodeFiles$1 as z };