create-krispya 0.13.0 → 0.15.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 +476 -188
- package/dist/cli.d.cts +2 -2
- package/dist/cli.d.mts +2 -2
- package/dist/cli.d.ts +2 -2
- package/dist/cli.mjs +483 -194
- package/dist/index.cjs +39 -1
- package/dist/index.d.cts +127 -7
- package/dist/index.d.mts +127 -7
- package/dist/index.d.ts +127 -7
- package/dist/index.mjs +2 -1
- package/dist/shared/{create-krispya.CcQTepKu.d.cts → create-krispya.8Jt7v_KA.d.cts} +1 -1
- package/dist/shared/{create-krispya.CcQTepKu.d.mts → create-krispya.8Jt7v_KA.d.mts} +1 -1
- package/dist/shared/{create-krispya.CcQTepKu.d.ts → create-krispya.8Jt7v_KA.d.ts} +1 -1
- package/dist/shared/{create-krispya.B2px1YOh.mjs → create-krispya.BYCdQkPo.mjs} +634 -380
- package/dist/shared/{create-krispya.CiGwBdQ3.cjs → create-krispya.Wf4wp5cQ.cjs} +664 -379
- package/package.json +9 -10
|
@@ -3,189 +3,32 @@
|
|
|
3
3
|
const promises = require('fs/promises');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const Conf = require('conf');
|
|
6
7
|
const color = require('chalk');
|
|
7
8
|
|
|
8
9
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
9
10
|
|
|
11
|
+
const Conf__default = /*#__PURE__*/_interopDefaultCompat(Conf);
|
|
10
12
|
const color__default = /*#__PURE__*/_interopDefaultCompat(color);
|
|
11
13
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"*.jpg binary",
|
|
16
|
-
"*.jpeg binary",
|
|
17
|
-
"*.gif binary",
|
|
18
|
-
"*.ico binary",
|
|
19
|
-
"*.mov binary",
|
|
20
|
-
"*.mp4 binary",
|
|
21
|
-
"*.mp3 binary",
|
|
22
|
-
"*.flv binary",
|
|
23
|
-
"*.fla binary",
|
|
24
|
-
"*.wav binary",
|
|
25
|
-
"*.swf binary",
|
|
26
|
-
"*.gz binary",
|
|
27
|
-
"*.zip binary",
|
|
28
|
-
"*.7z binary",
|
|
29
|
-
"*.ttf binary",
|
|
30
|
-
"*.eot binary",
|
|
31
|
-
"*.woff binary",
|
|
32
|
-
"*.pyc binary",
|
|
33
|
-
"*.pdf binary",
|
|
34
|
-
"*.glb binary",
|
|
35
|
-
"*.gltf binary"
|
|
36
|
-
].join("\n");
|
|
37
|
-
|
|
38
|
-
const ALL_AI_PLATFORMS = ["agents", "claude"];
|
|
39
|
-
const AI_PLATFORM_LABELS = {
|
|
40
|
-
agents: "AGENTS.md",
|
|
41
|
-
claude: "CLAUDE.md"
|
|
42
|
-
};
|
|
43
|
-
const AI_PLATFORM_HINTS = {
|
|
44
|
-
agents: "OpenAI, Cursor, Windsurf, etc.",
|
|
45
|
-
claude: "Claude Code"
|
|
46
|
-
};
|
|
47
|
-
function renderAiFiles(files, params) {
|
|
48
|
-
const { platforms, isMonorepo, configStrategy, hasTypecheck, ...rest } = params;
|
|
49
|
-
if (platforms.length === 0) return;
|
|
50
|
-
const content = generateWorkspace({
|
|
51
|
-
...rest,
|
|
52
|
-
isMonorepo: !!isMonorepo,
|
|
53
|
-
configStrategy: configStrategy ?? "stealth",
|
|
54
|
-
hasTypecheck: hasTypecheck ?? false
|
|
55
|
-
});
|
|
56
|
-
const pointer = "See [`AGENTS.md`](./Agents.md) for agent context.\n";
|
|
57
|
-
const hasAgents = platforms.includes("agents");
|
|
58
|
-
const hasClaude = platforms.includes("claude");
|
|
59
|
-
const isSingleton = platforms.length === 1;
|
|
60
|
-
if (hasAgents) files["AGENTS.md"] = { type: "text", content };
|
|
61
|
-
if (hasClaude) {
|
|
62
|
-
if (isSingleton) {
|
|
63
|
-
files["CLAUDE.md"] = { type: "text", content };
|
|
64
|
-
} else {
|
|
65
|
-
files["CLAUDE.md"] = { type: "text", content: pointer };
|
|
66
|
-
}
|
|
67
|
-
}
|
|
14
|
+
const PACKAGE_MANAGER_NAMES = /* @__PURE__ */ new Set(["pnpm", "npm", "yarn"]);
|
|
15
|
+
function isPackageManagerName(value) {
|
|
16
|
+
return PACKAGE_MANAGER_NAMES.has(value);
|
|
68
17
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const commands = getAfterEditingCommands(ctx, exampleFiles);
|
|
73
|
-
const sections = [
|
|
74
|
-
"# Workspace Tools",
|
|
75
|
-
"",
|
|
76
|
-
`- **Package Manager:** ${packageManager}`,
|
|
77
|
-
`- **Linter:** ${linter}`,
|
|
78
|
-
`- **Formatter:** ${formatter}`,
|
|
79
|
-
"",
|
|
80
|
-
"## After Editing",
|
|
81
|
-
""
|
|
82
|
-
];
|
|
83
|
-
if (hasTypecheck) {
|
|
84
|
-
sections.push(
|
|
85
|
-
"\u2705 After editing files, check the types for errors and then format and lint only the files changed for the current task."
|
|
86
|
-
);
|
|
87
|
-
} else {
|
|
88
|
-
sections.push(
|
|
89
|
-
"\u2705 After editing files, format and lint only the files changed for the current task."
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
sections.push("", "```sh", "# Example");
|
|
93
|
-
if (hasTypecheck) {
|
|
94
|
-
sections.push(runScript(packageManager, "typecheck"));
|
|
95
|
-
}
|
|
96
|
-
sections.push(
|
|
97
|
-
"# Run format and lint for only files modified",
|
|
98
|
-
commands.format,
|
|
99
|
-
commands.lint,
|
|
100
|
-
"```",
|
|
101
|
-
"",
|
|
102
|
-
"\u274C Avoid unless explicitly approved:",
|
|
103
|
-
"",
|
|
104
|
-
"```sh",
|
|
105
|
-
runScript(packageManager, "format"),
|
|
106
|
-
runScript(packageManager, "lint"),
|
|
107
|
-
"```",
|
|
108
|
-
""
|
|
109
|
-
);
|
|
110
|
-
return sections.join("\n");
|
|
111
|
-
}
|
|
112
|
-
function getAfterEditingCommands(ctx, files) {
|
|
113
|
-
return {
|
|
114
|
-
format: getFormatChangedFilesCommand(ctx, files),
|
|
115
|
-
lint: getLintChangedFilesCommand(ctx, files)
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
function getFormatChangedFilesCommand(ctx, files) {
|
|
119
|
-
const exec = getExecCommand(ctx.packageManager);
|
|
120
|
-
if (ctx.formatter === "prettier") {
|
|
121
|
-
const configPath = getPrettierConfigPath(ctx);
|
|
122
|
-
const ignorePath = getPrettierIgnorePath(ctx);
|
|
123
|
-
const configFlag2 = configPath == null ? "" : ` --config ${configPath}`;
|
|
124
|
-
const ignoreFlag = ignorePath == null ? "" : ` --ignore-path ${ignorePath}`;
|
|
125
|
-
return `${exec} prettier${configFlag2}${ignoreFlag} --write ${files}`;
|
|
126
|
-
}
|
|
127
|
-
if (ctx.formatter === "oxfmt") {
|
|
128
|
-
const configPath = getOxfmtConfigPath(ctx);
|
|
129
|
-
return `${exec} oxfmt -c ${configPath} --write ${files}`;
|
|
130
|
-
}
|
|
131
|
-
const configFlag = ctx.isMonorepo || ctx.configStrategy === "root" ? "" : " --config-path .config";
|
|
132
|
-
return `${exec} biome format${configFlag} --write ${files}`;
|
|
133
|
-
}
|
|
134
|
-
function getLintChangedFilesCommand(ctx, files) {
|
|
135
|
-
const exec = getExecCommand(ctx.packageManager);
|
|
136
|
-
if (ctx.linter === "oxlint") {
|
|
137
|
-
if (!ctx.isMonorepo) {
|
|
138
|
-
return runScript(ctx.packageManager, "lint", files);
|
|
139
|
-
}
|
|
140
|
-
return `${exec} oxlint ${files}`;
|
|
141
|
-
}
|
|
142
|
-
if (ctx.linter === "eslint") {
|
|
143
|
-
const configFlag2 = ctx.configStrategy === "stealth" ? " --config .config/eslint.config.js" : "";
|
|
144
|
-
return `${exec} eslint${configFlag2} ${files}`;
|
|
18
|
+
function parsePackageManagerSpec(value) {
|
|
19
|
+
if (value == null || value.length === 0) {
|
|
20
|
+
return void 0;
|
|
145
21
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (ctx.isMonorepo) return ".config/prettier/base.json";
|
|
151
|
-
if (ctx.configStrategy === "stealth") return ".config/prettier.json";
|
|
152
|
-
return void 0;
|
|
153
|
-
}
|
|
154
|
-
function getPrettierIgnorePath(ctx) {
|
|
155
|
-
if (ctx.isMonorepo) return ".config/prettier/prettierignore";
|
|
156
|
-
if (ctx.configStrategy === "stealth") return ".config/prettierignore";
|
|
157
|
-
return void 0;
|
|
158
|
-
}
|
|
159
|
-
function getOxfmtConfigPath(ctx) {
|
|
160
|
-
if (ctx.isMonorepo) return ".config/oxfmt/base.json";
|
|
161
|
-
if (ctx.configStrategy === "stealth") return ".config/oxfmt.json";
|
|
162
|
-
return "oxfmt.json";
|
|
163
|
-
}
|
|
164
|
-
function runScript(packageManager, script, args) {
|
|
165
|
-
const suffix = args == null ? "" : ` ${args}`;
|
|
166
|
-
if (packageManager === "npm") {
|
|
167
|
-
return `npm run ${script}${args == null ? "" : ` --${suffix}`}`;
|
|
22
|
+
const atIndex = value.indexOf("@");
|
|
23
|
+
const name = atIndex === -1 ? value : value.slice(0, atIndex);
|
|
24
|
+
if (!isPackageManagerName(name)) {
|
|
25
|
+
return void 0;
|
|
168
26
|
}
|
|
169
|
-
if (
|
|
170
|
-
return
|
|
27
|
+
if (atIndex === -1) {
|
|
28
|
+
return { name };
|
|
171
29
|
}
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
function getExecCommand(packageManager) {
|
|
175
|
-
if (packageManager === "npm") return "npm exec --";
|
|
176
|
-
if (packageManager === "yarn") return "yarn exec";
|
|
177
|
-
return `${packageManager} exec`;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function getLanguageFromTemplate(template) {
|
|
181
|
-
return template.endsWith("-js") ? "javascript" : "typescript";
|
|
182
|
-
}
|
|
183
|
-
function getBaseTemplate(template) {
|
|
184
|
-
return template.replace("-js", "");
|
|
185
|
-
}
|
|
186
|
-
function shouldEnableReactCompiler(options) {
|
|
187
|
-
const template = options.template ?? "vanilla";
|
|
188
|
-
return getBaseTemplate(template) === "react" && (options.projectType ?? "app") === "app";
|
|
30
|
+
const version = value.slice(atIndex + 1);
|
|
31
|
+
return version.length > 0 ? { name, version } : { name };
|
|
189
32
|
}
|
|
190
33
|
|
|
191
34
|
function unique(...array) {
|
|
@@ -274,6 +117,10 @@ function validatePackageName(name) {
|
|
|
274
117
|
}
|
|
275
118
|
return validateNameSegment(name, "Package name");
|
|
276
119
|
}
|
|
120
|
+
function getPackageDirectoryName(name) {
|
|
121
|
+
const slashIndex = name.indexOf("/");
|
|
122
|
+
return slashIndex === -1 ? name : name.slice(slashIndex + 1);
|
|
123
|
+
}
|
|
277
124
|
|
|
278
125
|
function generateRandomName() {
|
|
279
126
|
const adjectives = [
|
|
@@ -385,150 +232,600 @@ async function detectLinterFromConfig(root) {
|
|
|
385
232
|
return "biome";
|
|
386
233
|
}
|
|
387
234
|
}
|
|
388
|
-
return void 0;
|
|
235
|
+
return void 0;
|
|
236
|
+
}
|
|
237
|
+
async function detectFormatterFromConfig(root) {
|
|
238
|
+
if (await pathExists(path.join(root, ".config/prettier"))) return "prettier";
|
|
239
|
+
if (await pathExists(path.join(root, ".config/oxfmt"))) return "oxfmt";
|
|
240
|
+
if (await pathExists(path.join(root, "biome.json"))) {
|
|
241
|
+
try {
|
|
242
|
+
const content = await promises.readFile(path.join(root, "biome.json"), "utf-8");
|
|
243
|
+
const config = JSON.parse(content);
|
|
244
|
+
if (config.formatter?.enabled !== false) return "biome";
|
|
245
|
+
} catch {
|
|
246
|
+
return "biome";
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return void 0;
|
|
250
|
+
}
|
|
251
|
+
function detectLinterFromDeps(devDeps) {
|
|
252
|
+
if (!devDeps) return void 0;
|
|
253
|
+
if (devDeps["@biomejs/biome"]) return "biome";
|
|
254
|
+
if (devDeps.eslint) return "eslint";
|
|
255
|
+
if (devDeps.oxlint) return "oxlint";
|
|
256
|
+
return void 0;
|
|
257
|
+
}
|
|
258
|
+
function detectFormatterFromDeps(devDeps) {
|
|
259
|
+
if (!devDeps) return void 0;
|
|
260
|
+
if (devDeps["@biomejs/biome"]) return "biome";
|
|
261
|
+
if (devDeps.prettier) return "prettier";
|
|
262
|
+
if (devDeps.oxfmt) return "oxfmt";
|
|
263
|
+
return void 0;
|
|
264
|
+
}
|
|
265
|
+
async function detectTooling(root) {
|
|
266
|
+
try {
|
|
267
|
+
const pkgPath = path.join(root, "package.json");
|
|
268
|
+
const content = await promises.readFile(pkgPath, "utf-8");
|
|
269
|
+
const pkg = JSON.parse(content);
|
|
270
|
+
const linter = detectLinterFromScript(pkg.scripts?.lint) ?? await detectLinterFromConfig(root) ?? detectLinterFromDeps(pkg.devDependencies);
|
|
271
|
+
const formatter = detectFormatterFromScript(pkg.scripts?.format) ?? await detectFormatterFromConfig(root) ?? detectFormatterFromDeps(pkg.devDependencies);
|
|
272
|
+
return { linter, formatter };
|
|
273
|
+
} catch {
|
|
274
|
+
return { linter: void 0, formatter: void 0 };
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const DEFAULT_MINIMUM_RELEASE_AGE_MINUTES = 1440;
|
|
279
|
+
const MINUTE_IN_MS = 60 * 1e3;
|
|
280
|
+
function getMinimumReleaseAgeMinutes(options) {
|
|
281
|
+
return Math.max(0, options?.minimumReleaseAgeMinutes ?? DEFAULT_MINIMUM_RELEASE_AGE_MINUTES);
|
|
282
|
+
}
|
|
283
|
+
function isVersionOldEnough(version, time, options) {
|
|
284
|
+
const minimumReleaseAgeMinutes = getMinimumReleaseAgeMinutes(options);
|
|
285
|
+
if (minimumReleaseAgeMinutes === 0) return true;
|
|
286
|
+
const publishedAt = time?.[version];
|
|
287
|
+
if (publishedAt == null) return false;
|
|
288
|
+
const publishedTime = Date.parse(publishedAt);
|
|
289
|
+
if (!Number.isFinite(publishedTime)) return false;
|
|
290
|
+
return (options?.now ?? Date.now()) - publishedTime >= minimumReleaseAgeMinutes * MINUTE_IN_MS;
|
|
291
|
+
}
|
|
292
|
+
function getInstallableVersions(versions, time, options) {
|
|
293
|
+
return [...versions].filter((version) => isVersionOldEnough(version, time, options));
|
|
294
|
+
}
|
|
295
|
+
async function fetchNpmPackageMetadata(packageName) {
|
|
296
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}`);
|
|
297
|
+
return await response.json();
|
|
298
|
+
}
|
|
299
|
+
async function getLatestNpmVersion(packageName, fallback, options) {
|
|
300
|
+
try {
|
|
301
|
+
if (getMinimumReleaseAgeMinutes(options) === 0) {
|
|
302
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
|
|
303
|
+
const data2 = await response.json();
|
|
304
|
+
return data2.version;
|
|
305
|
+
}
|
|
306
|
+
const data = await fetchNpmPackageMetadata(packageName);
|
|
307
|
+
const latestVersion = data["dist-tags"]?.latest;
|
|
308
|
+
if (latestVersion != null && isVersionOldEnough(latestVersion, data.time, options)) {
|
|
309
|
+
return latestVersion;
|
|
310
|
+
}
|
|
311
|
+
const latestInstallableVersion = getInstallableVersions(
|
|
312
|
+
Object.keys(data.versions ?? {}),
|
|
313
|
+
data.time,
|
|
314
|
+
options
|
|
315
|
+
).sort((a, b) => compareNumericSemver(b, a))[0];
|
|
316
|
+
return latestInstallableVersion ?? fallback;
|
|
317
|
+
} catch {
|
|
318
|
+
return fallback;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function getSemverMajor(version) {
|
|
322
|
+
if (version == null) return void 0;
|
|
323
|
+
const major = Number.parseInt(version, 10);
|
|
324
|
+
return Number.isFinite(major) ? major : void 0;
|
|
325
|
+
}
|
|
326
|
+
function getSemverMajorString(version) {
|
|
327
|
+
return String(getSemverMajor(version) ?? version.split(".")[0]);
|
|
328
|
+
}
|
|
329
|
+
function compareNumericSemver(a, b) {
|
|
330
|
+
const aParts = a.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
331
|
+
const bParts = b.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
332
|
+
const maxLength = Math.max(aParts.length, bParts.length);
|
|
333
|
+
for (let index = 0; index < maxLength; index += 1) {
|
|
334
|
+
const difference = (aParts[index] ?? 0) - (bParts[index] ?? 0);
|
|
335
|
+
if (difference !== 0) {
|
|
336
|
+
return difference;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return 0;
|
|
340
|
+
}
|
|
341
|
+
function getLatestMatchingMajorVersion(versions, majorVersion, time, options) {
|
|
342
|
+
return getInstallableVersions(versions, time, options).filter((version) => version.split(".")[0] === majorVersion).sort((a, b) => compareNumericSemver(b, a))[0];
|
|
343
|
+
}
|
|
344
|
+
async function getLatestNpmMajorVersion(packageName, majorVersion, fallback, options) {
|
|
345
|
+
try {
|
|
346
|
+
const data = await fetchNpmPackageMetadata(packageName);
|
|
347
|
+
const latestMatchingVersion = getLatestMatchingMajorVersion(
|
|
348
|
+
Object.keys(data.versions ?? {}),
|
|
349
|
+
majorVersion,
|
|
350
|
+
data.time,
|
|
351
|
+
options
|
|
352
|
+
);
|
|
353
|
+
return latestMatchingVersion ?? fallback;
|
|
354
|
+
} catch {
|
|
355
|
+
return fallback;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
async function getLatestNpmMajorVersionAtOrBelow(packageName, majorVersion, fallback, options) {
|
|
359
|
+
try {
|
|
360
|
+
const data = await fetchNpmPackageMetadata(packageName);
|
|
361
|
+
const versions = Object.keys(data.versions ?? {});
|
|
362
|
+
const requestedMajor = getSemverMajor(majorVersion);
|
|
363
|
+
if (requestedMajor !== void 0) {
|
|
364
|
+
for (let major = requestedMajor; major >= 0; major -= 1) {
|
|
365
|
+
const latestMatchingVersion = getLatestMatchingMajorVersion(
|
|
366
|
+
versions,
|
|
367
|
+
String(major),
|
|
368
|
+
data.time,
|
|
369
|
+
options
|
|
370
|
+
);
|
|
371
|
+
if (latestMatchingVersion != null) {
|
|
372
|
+
return latestMatchingVersion;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return fallback;
|
|
377
|
+
} catch {
|
|
378
|
+
return fallback;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
async function getLatestPnpmVersion() {
|
|
382
|
+
return getLatestNpmVersion("pnpm", "10.11.0");
|
|
383
|
+
}
|
|
384
|
+
async function getLatestYarnVersion() {
|
|
385
|
+
return getLatestNpmVersion("yarn", "4.6.0");
|
|
386
|
+
}
|
|
387
|
+
async function getLatestNpmCliVersion() {
|
|
388
|
+
return getLatestNpmVersion("npm", "11.0.0");
|
|
389
|
+
}
|
|
390
|
+
async function getLatestNodeVersion() {
|
|
391
|
+
try {
|
|
392
|
+
const response = await fetch("https://nodejs.org/dist/index.json");
|
|
393
|
+
const data = await response.json();
|
|
394
|
+
const latestVersion = data[0];
|
|
395
|
+
if (latestVersion) {
|
|
396
|
+
return latestVersion.version.replace(/^v/, "");
|
|
397
|
+
}
|
|
398
|
+
return "25.0.0";
|
|
399
|
+
} catch {
|
|
400
|
+
return "25.0.0";
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function parseWorkspaceYamlContent(content) {
|
|
405
|
+
const directories = [];
|
|
406
|
+
let inPackagesSection = false;
|
|
407
|
+
for (const line of content.split("\n")) {
|
|
408
|
+
const trimmed = line.trim();
|
|
409
|
+
if (trimmed === "packages:") {
|
|
410
|
+
inPackagesSection = true;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
if (inPackagesSection && trimmed && !line.startsWith(" ") && !line.startsWith(" ") && !trimmed.startsWith("-")) {
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
if (inPackagesSection && trimmed.startsWith("-")) {
|
|
417
|
+
const entry = trimmed.slice(1).trim().replace(/^["']|["']$/g, "").replace(/^\.\//, "").replace(/\/\*.*$/, "");
|
|
418
|
+
if (entry && !entry.startsWith(".")) {
|
|
419
|
+
directories.push(entry);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return directories;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const pnpm10Capabilities = {
|
|
427
|
+
pnpmWorkspaceVersionPolicy: "manage-package-manager-versions",
|
|
428
|
+
pnpmBuildDependencyPolicy: "onlyBuiltDependencies"
|
|
429
|
+
};
|
|
430
|
+
const pnpm10Requirements = {
|
|
431
|
+
node: "18.12"
|
|
432
|
+
};
|
|
433
|
+
const pnpm11Capabilities = {
|
|
434
|
+
pnpmWorkspaceVersionPolicy: "pmOnFail",
|
|
435
|
+
pnpmBuildDependencyPolicy: "allowBuilds"
|
|
436
|
+
};
|
|
437
|
+
const pnpm11Requirements = {
|
|
438
|
+
node: "22.13"
|
|
439
|
+
};
|
|
440
|
+
function getPnpmCapabilities(major) {
|
|
441
|
+
switch (major) {
|
|
442
|
+
case 10:
|
|
443
|
+
return pnpm10Capabilities;
|
|
444
|
+
case 11:
|
|
445
|
+
return pnpm11Capabilities;
|
|
446
|
+
default:
|
|
447
|
+
if (major != null && major >= 12) return pnpm11Capabilities;
|
|
448
|
+
else return pnpm10Capabilities;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
function getPnpmRequirements(major) {
|
|
452
|
+
switch (major) {
|
|
453
|
+
case 10:
|
|
454
|
+
return pnpm10Requirements;
|
|
455
|
+
case 11:
|
|
456
|
+
return pnpm11Requirements;
|
|
457
|
+
default:
|
|
458
|
+
if (major != null && major >= 12) return pnpm11Requirements;
|
|
459
|
+
else return pnpm10Requirements;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function getPnpmProfile(spec) {
|
|
463
|
+
const major = getSemverMajor(spec.version);
|
|
464
|
+
return {
|
|
465
|
+
...spec,
|
|
466
|
+
major,
|
|
467
|
+
capabilities: getPnpmCapabilities(major),
|
|
468
|
+
requirements: getPnpmRequirements(major)
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
function renderPnpmWorkspaceConfig(options) {
|
|
472
|
+
const {
|
|
473
|
+
profile,
|
|
474
|
+
manageVersions = true,
|
|
475
|
+
packages = [],
|
|
476
|
+
buildDependencies = { esbuild: true }
|
|
477
|
+
} = options;
|
|
478
|
+
const lines = [];
|
|
479
|
+
if (manageVersions) {
|
|
480
|
+
if (profile.capabilities.pnpmWorkspaceVersionPolicy === "pmOnFail") {
|
|
481
|
+
lines.push("pmOnFail: download", "");
|
|
482
|
+
} else {
|
|
483
|
+
lines.push("manage-package-manager-versions: true", "");
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (packages.length > 0) {
|
|
487
|
+
lines.push("packages:", ...packages.map((pattern) => ` - "${pattern}"`), "");
|
|
488
|
+
}
|
|
489
|
+
if (profile.capabilities.pnpmBuildDependencyPolicy === "allowBuilds") {
|
|
490
|
+
lines.push("allowBuilds:");
|
|
491
|
+
for (const [dependency, allowed] of Object.entries(buildDependencies)) {
|
|
492
|
+
lines.push(` ${dependency}: ${allowed ? "true" : "false"}`);
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
const allowedDependencies = Object.entries(buildDependencies).filter(([, allowed]) => allowed).map(([dependency]) => dependency);
|
|
496
|
+
lines.push("onlyBuiltDependencies:");
|
|
497
|
+
for (const dependency of allowedDependencies) {
|
|
498
|
+
lines.push(` - ${dependency}`);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return lines.join("\n");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function getPackageManagerProfile(spec) {
|
|
505
|
+
const major = getSemverMajor(spec.version);
|
|
506
|
+
if (spec.name === "pnpm") {
|
|
507
|
+
return getPnpmProfile(spec);
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
...spec,
|
|
511
|
+
major,
|
|
512
|
+
capabilities: {},
|
|
513
|
+
requirements: {}
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function getPackageManagerSpec(packageManager) {
|
|
518
|
+
return packageManager ?? { name: "pnpm" };
|
|
519
|
+
}
|
|
520
|
+
function getPackageManagerName(packageManager) {
|
|
521
|
+
return getPackageManagerSpec(packageManager).name;
|
|
522
|
+
}
|
|
523
|
+
function formatPackageManager(packageManager) {
|
|
524
|
+
const spec = getPackageManagerSpec(packageManager);
|
|
525
|
+
return spec.version ? `${spec.name}@${spec.version}` : spec.name;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
async function resolvePackageManager(options) {
|
|
529
|
+
const packageManager = getPackageManagerSpec(options.packageManager);
|
|
530
|
+
if (packageManager.version == null) {
|
|
531
|
+
if (packageManager.name === "pnpm") {
|
|
532
|
+
packageManager.version = await getLatestPnpmVersion();
|
|
533
|
+
} else if (packageManager.name === "yarn") {
|
|
534
|
+
packageManager.version = await getLatestYarnVersion();
|
|
535
|
+
} else if (packageManager.name === "npm") {
|
|
536
|
+
packageManager.version = await getLatestNpmCliVersion();
|
|
537
|
+
}
|
|
538
|
+
} else if (/^\d+$/.test(packageManager.version)) {
|
|
539
|
+
const fallback = `${packageManager.version}.0.0`;
|
|
540
|
+
packageManager.version = await getLatestNpmMajorVersion(
|
|
541
|
+
packageManager.name,
|
|
542
|
+
packageManager.version,
|
|
543
|
+
fallback
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
return packageManager;
|
|
547
|
+
}
|
|
548
|
+
async function resolvePackageManagerProfile(options) {
|
|
549
|
+
return getPackageManagerProfile(await resolvePackageManager(options));
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function getEngineSpec(engine) {
|
|
553
|
+
return engine ?? { name: "node" };
|
|
554
|
+
}
|
|
555
|
+
function getEngineName(engine) {
|
|
556
|
+
return getEngineSpec(engine).name;
|
|
557
|
+
}
|
|
558
|
+
function formatEngine(engine) {
|
|
559
|
+
const spec = getEngineSpec(engine);
|
|
560
|
+
return spec.version ? `${spec.name}@${spec.version}` : spec.name;
|
|
561
|
+
}
|
|
562
|
+
function parseEngine(engines) {
|
|
563
|
+
if (engines == null) {
|
|
564
|
+
return void 0;
|
|
565
|
+
}
|
|
566
|
+
const [name, range] = Object.entries(engines).find(
|
|
567
|
+
([engineName]) => engineName !== "npm" && engineName !== "pnpm" && engineName !== "yarn"
|
|
568
|
+
) ?? [];
|
|
569
|
+
if (name == null) {
|
|
570
|
+
return void 0;
|
|
571
|
+
}
|
|
572
|
+
const version = range?.match(/(\d+(?:\.\d+(?:\.\d+)?)?)/)?.[1];
|
|
573
|
+
return { name, version };
|
|
574
|
+
}
|
|
575
|
+
async function resolveEngine(options) {
|
|
576
|
+
const engine = getEngineSpec(options.engine);
|
|
577
|
+
if ((engine.version == null || engine.version === "latest") && engine.name === "node") {
|
|
578
|
+
engine.version = await getLatestNodeVersion();
|
|
579
|
+
}
|
|
580
|
+
return engine;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function getLanguageFromTemplate(template) {
|
|
584
|
+
return template.endsWith("-js") ? "javascript" : "typescript";
|
|
585
|
+
}
|
|
586
|
+
function getBaseTemplate(template) {
|
|
587
|
+
return template.replace("-js", "");
|
|
588
|
+
}
|
|
589
|
+
function shouldEnableReactCompiler(options) {
|
|
590
|
+
const template = options.template ?? "vanilla";
|
|
591
|
+
return getBaseTemplate(template) === "react" && (options.projectType ?? "app") === "app";
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const config = new Conf__default({
|
|
595
|
+
projectName: "create-krispya"
|
|
596
|
+
});
|
|
597
|
+
function getAiPlatforms() {
|
|
598
|
+
return config.get("aiPlatforms");
|
|
599
|
+
}
|
|
600
|
+
function setAiPlatforms(platforms) {
|
|
601
|
+
config.set("aiPlatforms", platforms);
|
|
602
|
+
}
|
|
603
|
+
function getConfigStrategy() {
|
|
604
|
+
return config.get("configStrategy") ?? "stealth";
|
|
605
|
+
}
|
|
606
|
+
function setConfigStrategy(strategy) {
|
|
607
|
+
config.set("configStrategy", strategy);
|
|
608
|
+
}
|
|
609
|
+
function clearConfig() {
|
|
610
|
+
config.clear();
|
|
611
|
+
}
|
|
612
|
+
function getConfigPath() {
|
|
613
|
+
return config.path;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const ALL_AI_PLATFORMS = ["agents", "claude"];
|
|
617
|
+
const AI_PLATFORM_LABELS = {
|
|
618
|
+
agents: "AGENTS.md",
|
|
619
|
+
claude: "CLAUDE.md"
|
|
620
|
+
};
|
|
621
|
+
const AI_PLATFORM_HINTS = {
|
|
622
|
+
agents: "OpenAI, Cursor, Windsurf, etc.",
|
|
623
|
+
claude: "Claude Code"
|
|
624
|
+
};
|
|
625
|
+
function renderAiFiles(files, params) {
|
|
626
|
+
const { platforms, isMonorepo, configStrategy, hasTypecheck, ...rest } = params;
|
|
627
|
+
if (platforms.length === 0) return;
|
|
628
|
+
const content = generateWorkspace({
|
|
629
|
+
...rest,
|
|
630
|
+
isMonorepo: !!isMonorepo,
|
|
631
|
+
configStrategy: configStrategy ?? "stealth",
|
|
632
|
+
hasTypecheck: hasTypecheck ?? false
|
|
633
|
+
});
|
|
634
|
+
const pointer = "See [`AGENTS.md`](./Agents.md) for agent context.\n";
|
|
635
|
+
const hasAgents = platforms.includes("agents");
|
|
636
|
+
const hasClaude = platforms.includes("claude");
|
|
637
|
+
const isSingleton = platforms.length === 1;
|
|
638
|
+
if (hasAgents) files["AGENTS.md"] = { type: "text", content };
|
|
639
|
+
if (hasClaude) {
|
|
640
|
+
if (isSingleton) {
|
|
641
|
+
files["CLAUDE.md"] = { type: "text", content };
|
|
642
|
+
} else {
|
|
643
|
+
files["CLAUDE.md"] = { type: "text", content: pointer };
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
function generateWorkspace(ctx) {
|
|
648
|
+
const { packageManager, linter, formatter, hasTypecheck } = ctx;
|
|
649
|
+
const exampleFiles = "src/App.tsx src/core/systems/move-entity.ts";
|
|
650
|
+
const commands = getAfterEditingCommands(ctx, exampleFiles);
|
|
651
|
+
const sections = [
|
|
652
|
+
"# Workspace Tools",
|
|
653
|
+
"",
|
|
654
|
+
`- **Package Manager:** ${packageManager}`,
|
|
655
|
+
`- **Linter:** ${linter}`,
|
|
656
|
+
`- **Formatter:** ${formatter}`,
|
|
657
|
+
"",
|
|
658
|
+
"## After Editing",
|
|
659
|
+
""
|
|
660
|
+
];
|
|
661
|
+
if (hasTypecheck) {
|
|
662
|
+
sections.push(
|
|
663
|
+
"\u2705 After editing files, check the types for errors and then format and lint only the files changed for the current task."
|
|
664
|
+
);
|
|
665
|
+
} else {
|
|
666
|
+
sections.push(
|
|
667
|
+
"\u2705 After editing files, format and lint only the files changed for the current task."
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
sections.push("", "```sh", "# Example");
|
|
671
|
+
if (hasTypecheck) {
|
|
672
|
+
sections.push(runScript(packageManager, "typecheck"));
|
|
673
|
+
}
|
|
674
|
+
sections.push(
|
|
675
|
+
"# Run format and lint for only files modified",
|
|
676
|
+
commands.format,
|
|
677
|
+
commands.lint,
|
|
678
|
+
"```",
|
|
679
|
+
"",
|
|
680
|
+
"\u274C Avoid unless explicitly approved:",
|
|
681
|
+
"",
|
|
682
|
+
"```sh",
|
|
683
|
+
runScript(packageManager, "format"),
|
|
684
|
+
runScript(packageManager, "lint"),
|
|
685
|
+
"```",
|
|
686
|
+
""
|
|
687
|
+
);
|
|
688
|
+
return sections.join("\n");
|
|
689
|
+
}
|
|
690
|
+
function getAfterEditingCommands(ctx, files) {
|
|
691
|
+
return {
|
|
692
|
+
format: getFormatChangedFilesCommand(ctx, files),
|
|
693
|
+
lint: getLintChangedFilesCommand(ctx, files)
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function getFormatChangedFilesCommand(ctx, files) {
|
|
697
|
+
const exec = getExecCommand(ctx.packageManager);
|
|
698
|
+
if (ctx.formatter === "prettier") {
|
|
699
|
+
const configPath = getPrettierConfigPath(ctx);
|
|
700
|
+
const ignorePath = getPrettierIgnorePath(ctx);
|
|
701
|
+
const configFlag2 = configPath == null ? "" : ` --config ${configPath}`;
|
|
702
|
+
const ignoreFlag = ignorePath == null ? "" : ` --ignore-path ${ignorePath}`;
|
|
703
|
+
return `${exec} prettier${configFlag2}${ignoreFlag} --write ${files}`;
|
|
704
|
+
}
|
|
705
|
+
if (ctx.formatter === "oxfmt") {
|
|
706
|
+
const configPath = getOxfmtConfigPath(ctx);
|
|
707
|
+
return `${exec} oxfmt -c ${configPath} --write ${files}`;
|
|
708
|
+
}
|
|
709
|
+
const configFlag = ctx.isMonorepo || ctx.configStrategy === "root" ? "" : " --config-path .config";
|
|
710
|
+
return `${exec} biome format${configFlag} --write ${files}`;
|
|
389
711
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if (
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
const content = await promises.readFile(path.join(root, "biome.json"), "utf-8");
|
|
396
|
-
const config = JSON.parse(content);
|
|
397
|
-
if (config.formatter?.enabled !== false) return "biome";
|
|
398
|
-
} catch {
|
|
399
|
-
return "biome";
|
|
712
|
+
function getLintChangedFilesCommand(ctx, files) {
|
|
713
|
+
const exec = getExecCommand(ctx.packageManager);
|
|
714
|
+
if (ctx.linter === "oxlint") {
|
|
715
|
+
if (!ctx.isMonorepo) {
|
|
716
|
+
return runScript(ctx.packageManager, "lint", files);
|
|
400
717
|
}
|
|
718
|
+
return `${exec} oxlint ${files}`;
|
|
401
719
|
}
|
|
402
|
-
|
|
720
|
+
if (ctx.linter === "eslint") {
|
|
721
|
+
const configFlag2 = ctx.configStrategy === "stealth" ? " --config .config/eslint.config.js" : "";
|
|
722
|
+
return `${exec} eslint${configFlag2} ${files}`;
|
|
723
|
+
}
|
|
724
|
+
const configFlag = ctx.isMonorepo || ctx.configStrategy === "root" ? "" : " --config-path .config";
|
|
725
|
+
return `${exec} biome lint${configFlag} ${files}`;
|
|
403
726
|
}
|
|
404
|
-
function
|
|
405
|
-
if (
|
|
406
|
-
if (
|
|
407
|
-
if (devDeps.eslint) return "eslint";
|
|
408
|
-
if (devDeps.oxlint) return "oxlint";
|
|
727
|
+
function getPrettierConfigPath(ctx) {
|
|
728
|
+
if (ctx.isMonorepo) return ".config/prettier/base.json";
|
|
729
|
+
if (ctx.configStrategy === "stealth") return ".config/prettier.json";
|
|
409
730
|
return void 0;
|
|
410
731
|
}
|
|
411
|
-
function
|
|
412
|
-
if (
|
|
413
|
-
if (
|
|
414
|
-
if (devDeps.prettier) return "prettier";
|
|
415
|
-
if (devDeps.oxfmt) return "oxfmt";
|
|
732
|
+
function getPrettierIgnorePath(ctx) {
|
|
733
|
+
if (ctx.isMonorepo) return ".config/prettier/prettierignore";
|
|
734
|
+
if (ctx.configStrategy === "stealth") return ".config/prettierignore";
|
|
416
735
|
return void 0;
|
|
417
736
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const pkg = JSON.parse(content);
|
|
423
|
-
const linter = detectLinterFromScript(pkg.scripts?.lint) ?? await detectLinterFromConfig(root) ?? detectLinterFromDeps(pkg.devDependencies);
|
|
424
|
-
const formatter = detectFormatterFromScript(pkg.scripts?.format) ?? await detectFormatterFromConfig(root) ?? detectFormatterFromDeps(pkg.devDependencies);
|
|
425
|
-
return { linter, formatter };
|
|
426
|
-
} catch {
|
|
427
|
-
return { linter: void 0, formatter: void 0 };
|
|
428
|
-
}
|
|
737
|
+
function getOxfmtConfigPath(ctx) {
|
|
738
|
+
if (ctx.isMonorepo) return ".config/oxfmt/base.json";
|
|
739
|
+
if (ctx.configStrategy === "stealth") return ".config/oxfmt.json";
|
|
740
|
+
return "oxfmt.json";
|
|
429
741
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const data = await response.json();
|
|
435
|
-
return data.version;
|
|
436
|
-
} catch {
|
|
437
|
-
return fallback;
|
|
742
|
+
function runScript(packageManager, script, args) {
|
|
743
|
+
const suffix = args == null ? "" : ` ${args}`;
|
|
744
|
+
if (packageManager === "npm") {
|
|
745
|
+
return `npm run ${script}${args == null ? "" : ` --${suffix}`}`;
|
|
438
746
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
const aParts = a.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
442
|
-
const bParts = b.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
443
|
-
const maxLength = Math.max(aParts.length, bParts.length);
|
|
444
|
-
for (let index = 0; index < maxLength; index += 1) {
|
|
445
|
-
const difference = (aParts[index] ?? 0) - (bParts[index] ?? 0);
|
|
446
|
-
if (difference !== 0) {
|
|
447
|
-
return difference;
|
|
448
|
-
}
|
|
747
|
+
if (packageManager === "yarn") {
|
|
748
|
+
return `yarn ${script}${suffix}`;
|
|
449
749
|
}
|
|
450
|
-
return
|
|
451
|
-
}
|
|
452
|
-
function getLatestMatchingMajorVersion(versions, majorVersion) {
|
|
453
|
-
return [...versions].filter((version) => version.split(".")[0] === majorVersion).sort((a, b) => compareNumericSemver(b, a))[0];
|
|
750
|
+
return `${packageManager} ${script}${args == null ? "" : ` --${suffix}`}`;
|
|
454
751
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const latestMatchingVersion = getLatestMatchingMajorVersion(
|
|
460
|
-
Object.keys(data.versions ?? {}),
|
|
461
|
-
majorVersion
|
|
462
|
-
);
|
|
463
|
-
return latestMatchingVersion ?? fallback;
|
|
464
|
-
} catch {
|
|
465
|
-
return fallback;
|
|
466
|
-
}
|
|
752
|
+
function getExecCommand(packageManager) {
|
|
753
|
+
if (packageManager === "npm") return "npm exec --";
|
|
754
|
+
if (packageManager === "yarn") return "yarn exec";
|
|
755
|
+
return `${packageManager} exec`;
|
|
467
756
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
for (let major = requestedMajor; major >= 0; major -= 1) {
|
|
476
|
-
const latestMatchingVersion = getLatestMatchingMajorVersion(versions, String(major));
|
|
477
|
-
if (latestMatchingVersion != null) {
|
|
478
|
-
return latestMatchingVersion;
|
|
479
|
-
}
|
|
480
|
-
}
|
|
757
|
+
|
|
758
|
+
async function checkAnyExists(paths) {
|
|
759
|
+
for (const path of paths) {
|
|
760
|
+
try {
|
|
761
|
+
await promises.access(path, promises.constants.F_OK);
|
|
762
|
+
return true;
|
|
763
|
+
} catch {
|
|
481
764
|
}
|
|
482
|
-
return fallback;
|
|
483
|
-
} catch {
|
|
484
|
-
return fallback;
|
|
485
765
|
}
|
|
766
|
+
return false;
|
|
486
767
|
}
|
|
487
|
-
async function
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
async function getLatestYarnVersion() {
|
|
491
|
-
return getLatestNpmVersion("yarn", "4.6.0");
|
|
492
|
-
}
|
|
493
|
-
async function getLatestNpmCliVersion() {
|
|
494
|
-
return getLatestNpmVersion("npm", "11.0.0");
|
|
495
|
-
}
|
|
496
|
-
async function getLatestNodeVersion() {
|
|
768
|
+
async function validateWorkspace(monorepoRoot) {
|
|
769
|
+
const errors = [];
|
|
770
|
+
const tsConfigPath = path.join(monorepoRoot, ".config/typescript/package.json");
|
|
497
771
|
try {
|
|
498
|
-
|
|
499
|
-
const data = await response.json();
|
|
500
|
-
const latestVersion = data[0];
|
|
501
|
-
if (latestVersion) {
|
|
502
|
-
return latestVersion.version.replace(/^v/, "");
|
|
503
|
-
}
|
|
504
|
-
return "25.0.0";
|
|
772
|
+
await promises.access(tsConfigPath, promises.constants.F_OK);
|
|
505
773
|
} catch {
|
|
506
|
-
|
|
774
|
+
errors.push("Missing .config/typescript package");
|
|
507
775
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (inPackagesSection && trimmed && !line.startsWith(" ") && !line.startsWith(" ") && !trimmed.startsWith("-")) {
|
|
520
|
-
break;
|
|
521
|
-
}
|
|
522
|
-
if (inPackagesSection && trimmed.startsWith("-")) {
|
|
523
|
-
const entry = trimmed.slice(1).trim().replace(/^["']|["']$/g, "").replace(/^\.\//, "").replace(/\/\*.*$/, "");
|
|
524
|
-
if (entry && !entry.startsWith(".")) {
|
|
525
|
-
directories.push(entry);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
776
|
+
const linterPaths = [
|
|
777
|
+
path.join(monorepoRoot, ".config/oxlint/package.json"),
|
|
778
|
+
path.join(monorepoRoot, ".config/eslint/package.json"),
|
|
779
|
+
path.join(monorepoRoot, "eslint.config.js"),
|
|
780
|
+
path.join(monorepoRoot, "biome.json")
|
|
781
|
+
];
|
|
782
|
+
const hasLinter = await checkAnyExists(linterPaths);
|
|
783
|
+
if (!hasLinter) {
|
|
784
|
+
errors.push(
|
|
785
|
+
"Missing linter config (.config/oxlint, .config/eslint, eslint.config.js, or biome.json)"
|
|
786
|
+
);
|
|
528
787
|
}
|
|
529
|
-
|
|
788
|
+
const formatterPaths = [
|
|
789
|
+
path.join(monorepoRoot, ".config/oxfmt/package.json"),
|
|
790
|
+
path.join(monorepoRoot, ".config/prettier/package.json"),
|
|
791
|
+
path.join(monorepoRoot, ".prettierrc.json"),
|
|
792
|
+
path.join(monorepoRoot, "biome.json")
|
|
793
|
+
];
|
|
794
|
+
const hasFormatter = await checkAnyExists(formatterPaths);
|
|
795
|
+
if (!hasFormatter) {
|
|
796
|
+
errors.push(
|
|
797
|
+
"Missing formatter config (.config/oxfmt, .config/prettier, .prettierrc.json, or biome.json)"
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
return { valid: errors.length === 0, errors };
|
|
530
801
|
}
|
|
531
802
|
|
|
803
|
+
const gitAttributesContent = [
|
|
804
|
+
"* text eol=lf",
|
|
805
|
+
"*.png binary",
|
|
806
|
+
"*.jpg binary",
|
|
807
|
+
"*.jpeg binary",
|
|
808
|
+
"*.gif binary",
|
|
809
|
+
"*.ico binary",
|
|
810
|
+
"*.mov binary",
|
|
811
|
+
"*.mp4 binary",
|
|
812
|
+
"*.mp3 binary",
|
|
813
|
+
"*.flv binary",
|
|
814
|
+
"*.fla binary",
|
|
815
|
+
"*.wav binary",
|
|
816
|
+
"*.swf binary",
|
|
817
|
+
"*.gz binary",
|
|
818
|
+
"*.zip binary",
|
|
819
|
+
"*.7z binary",
|
|
820
|
+
"*.ttf binary",
|
|
821
|
+
"*.eot binary",
|
|
822
|
+
"*.woff binary",
|
|
823
|
+
"*.pyc binary",
|
|
824
|
+
"*.pdf binary",
|
|
825
|
+
"*.glb binary",
|
|
826
|
+
"*.gltf binary"
|
|
827
|
+
].join("\n");
|
|
828
|
+
|
|
532
829
|
const PACKAGE_VERSION_DEFINITIONS = {
|
|
533
830
|
"@babel/core": { fallbackVersion: "7.29.0" },
|
|
534
831
|
"@biomejs/biome": { fallbackVersion: "2.0.0" },
|
|
@@ -600,68 +897,6 @@ function formatResolvedPackageVersion(versions, packageName, prefix) {
|
|
|
600
897
|
function assignResolvedPackageVersion(target, versions, packageName, prefix) {
|
|
601
898
|
target[packageName] = formatResolvedPackageVersion(versions, packageName, prefix);
|
|
602
899
|
}
|
|
603
|
-
function getPackageManagerSpec(packageManager) {
|
|
604
|
-
return packageManager ?? { name: "pnpm" };
|
|
605
|
-
}
|
|
606
|
-
function getPackageManagerName(packageManager) {
|
|
607
|
-
return getPackageManagerSpec(packageManager).name;
|
|
608
|
-
}
|
|
609
|
-
function formatPackageManager(packageManager) {
|
|
610
|
-
const spec = getPackageManagerSpec(packageManager);
|
|
611
|
-
return spec.version ? `${spec.name}@${spec.version}` : spec.name;
|
|
612
|
-
}
|
|
613
|
-
function parsePackageManager(packageManager) {
|
|
614
|
-
if (packageManager == null || packageManager.length === 0) {
|
|
615
|
-
return void 0;
|
|
616
|
-
}
|
|
617
|
-
const atIndex = packageManager.indexOf("@");
|
|
618
|
-
if (atIndex === -1) {
|
|
619
|
-
return { name: packageManager };
|
|
620
|
-
}
|
|
621
|
-
return {
|
|
622
|
-
name: packageManager.slice(0, atIndex),
|
|
623
|
-
version: packageManager.slice(atIndex + 1)
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
function getEngineSpec(engine) {
|
|
627
|
-
return engine ?? { name: "node" };
|
|
628
|
-
}
|
|
629
|
-
function getEngineName(engine) {
|
|
630
|
-
return getEngineSpec(engine).name;
|
|
631
|
-
}
|
|
632
|
-
function parseEngine(engines) {
|
|
633
|
-
if (engines == null) {
|
|
634
|
-
return void 0;
|
|
635
|
-
}
|
|
636
|
-
const [name, range] = Object.entries(engines).find(
|
|
637
|
-
([engineName]) => engineName !== "npm" && engineName !== "pnpm" && engineName !== "yarn"
|
|
638
|
-
) ?? [];
|
|
639
|
-
if (name == null) {
|
|
640
|
-
return void 0;
|
|
641
|
-
}
|
|
642
|
-
const version = range?.match(/(\d+(?:\.\d+(?:\.\d+)?)?)/)?.[1];
|
|
643
|
-
return { name, version };
|
|
644
|
-
}
|
|
645
|
-
async function resolvePackageManager(options) {
|
|
646
|
-
const packageManager = getPackageManagerSpec(options.packageManager);
|
|
647
|
-
if (packageManager.version == null) {
|
|
648
|
-
if (packageManager.name === "pnpm") {
|
|
649
|
-
packageManager.version = await getLatestPnpmVersion();
|
|
650
|
-
} else if (packageManager.name === "yarn") {
|
|
651
|
-
packageManager.version = await getLatestYarnVersion();
|
|
652
|
-
} else if (packageManager.name === "npm") {
|
|
653
|
-
packageManager.version = await getLatestNpmCliVersion();
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
return packageManager;
|
|
657
|
-
}
|
|
658
|
-
async function resolveEngine(options) {
|
|
659
|
-
const engine = getEngineSpec(options.engine);
|
|
660
|
-
if ((engine.version == null || engine.version === "latest") && engine.name === "node") {
|
|
661
|
-
engine.version = await getLatestNodeVersion();
|
|
662
|
-
}
|
|
663
|
-
return engine;
|
|
664
|
-
}
|
|
665
900
|
function formatNodeTypesVersion(versions = {}, _engine) {
|
|
666
901
|
const resolvedVersion = versions["@types/node"];
|
|
667
902
|
if (resolvedVersion != null) {
|
|
@@ -678,7 +913,7 @@ async function resolveNodeTypesVersion(engine, versions = {}) {
|
|
|
678
913
|
return void 0;
|
|
679
914
|
}
|
|
680
915
|
const nodeVersion = engineSpec.version ?? await getLatestNodeVersion();
|
|
681
|
-
const majorVersion = nodeVersion
|
|
916
|
+
const majorVersion = getSemverMajorString(nodeVersion);
|
|
682
917
|
return getLatestNpmMajorVersionAtOrBelow(
|
|
683
918
|
"@types/node",
|
|
684
919
|
majorVersion,
|
|
@@ -1201,12 +1436,12 @@ function renderPackageJson(params) {
|
|
|
1201
1436
|
if (!isMonorepoPackage) {
|
|
1202
1437
|
const engines = {};
|
|
1203
1438
|
if (packageManager.version != null) {
|
|
1204
|
-
const majorVersion = packageManager.version
|
|
1439
|
+
const majorVersion = getSemverMajorString(packageManager.version);
|
|
1205
1440
|
engines[packageManager.name] = `>=${majorVersion}.0.0`;
|
|
1206
1441
|
packageJson.packageManager = formatPackageManager(packageManager);
|
|
1207
1442
|
}
|
|
1208
1443
|
if (engine.version != null) {
|
|
1209
|
-
const majorVersion = engine.version
|
|
1444
|
+
const majorVersion = getSemverMajorString(engine.version);
|
|
1210
1445
|
engines[engine.name] = `>=${majorVersion}.0.0`;
|
|
1211
1446
|
}
|
|
1212
1447
|
if (Object.keys(engines).length > 0) {
|
|
@@ -1218,15 +1453,12 @@ function renderPackageJson(params) {
|
|
|
1218
1453
|
content: JSON.stringify(packageJson, null, 2)
|
|
1219
1454
|
};
|
|
1220
1455
|
if (isPnpm && !options.workspaceRoot) {
|
|
1221
|
-
const manageVersions = options.pnpmManageVersions ?? true;
|
|
1222
|
-
const workspaceLines = [];
|
|
1223
|
-
if (manageVersions) {
|
|
1224
|
-
workspaceLines.push("manage-package-manager-versions: true", "");
|
|
1225
|
-
}
|
|
1226
|
-
workspaceLines.push("onlyBuiltDependencies:", " - esbuild");
|
|
1227
1456
|
files["pnpm-workspace.yaml"] = {
|
|
1228
1457
|
type: "text",
|
|
1229
|
-
content:
|
|
1458
|
+
content: renderPnpmWorkspaceConfig({
|
|
1459
|
+
profile: getPackageManagerProfile(packageManager),
|
|
1460
|
+
manageVersions: options.pnpmManageVersions ?? true
|
|
1461
|
+
})
|
|
1230
1462
|
};
|
|
1231
1463
|
}
|
|
1232
1464
|
return { files };
|
|
@@ -2375,12 +2607,12 @@ function renderMonorepo(params) {
|
|
|
2375
2607
|
};
|
|
2376
2608
|
const engines = {};
|
|
2377
2609
|
if (isPnpm && packageManager.version) {
|
|
2378
|
-
const majorVersion = packageManager.version
|
|
2610
|
+
const majorVersion = getSemverMajorString(packageManager.version);
|
|
2379
2611
|
engines.pnpm = `>=${majorVersion}.0.0`;
|
|
2380
2612
|
rootPackageJson.packageManager = formatPackageManager(packageManager);
|
|
2381
2613
|
}
|
|
2382
2614
|
if (engine?.version) {
|
|
2383
|
-
const majorVersion = engine.version
|
|
2615
|
+
const majorVersion = getSemverMajorString(engine.version);
|
|
2384
2616
|
engines[engine.name] = `>=${majorVersion}.0.0`;
|
|
2385
2617
|
}
|
|
2386
2618
|
if (Object.keys(engines).length > 0) {
|
|
@@ -2391,15 +2623,13 @@ function renderMonorepo(params) {
|
|
|
2391
2623
|
content: JSON.stringify(rootPackageJson, null, 2)
|
|
2392
2624
|
};
|
|
2393
2625
|
if (isPnpm) {
|
|
2394
|
-
const workspaceLines = [];
|
|
2395
|
-
if (pnpmManageVersions) {
|
|
2396
|
-
workspaceLines.push("manage-package-manager-versions: true", "");
|
|
2397
|
-
}
|
|
2398
|
-
workspaceLines.push("packages:", ' - ".config/*"', ' - "apps/*"', ' - "packages/*"', "");
|
|
2399
|
-
workspaceLines.push("onlyBuiltDependencies:", " - esbuild");
|
|
2400
2626
|
files["pnpm-workspace.yaml"] = {
|
|
2401
2627
|
type: "text",
|
|
2402
|
-
content:
|
|
2628
|
+
content: renderPnpmWorkspaceConfig({
|
|
2629
|
+
profile: getPackageManagerProfile(packageManager),
|
|
2630
|
+
manageVersions: pnpmManageVersions,
|
|
2631
|
+
packages: [".config/*", "apps/*", "packages/*"]
|
|
2632
|
+
})
|
|
2403
2633
|
};
|
|
2404
2634
|
}
|
|
2405
2635
|
files["tsconfig.json"] = {
|
|
@@ -3624,6 +3854,21 @@ async function resolveWorkspaceFacts(input) {
|
|
|
3624
3854
|
});
|
|
3625
3855
|
}
|
|
3626
3856
|
|
|
3857
|
+
function materializeJobs(jobs) {
|
|
3858
|
+
const files = {};
|
|
3859
|
+
for (const job of jobs) {
|
|
3860
|
+
if (job.type === "write-file") {
|
|
3861
|
+
files[job.path] = job.file;
|
|
3862
|
+
} else if (job.type === "merge-pnpm-workspace") {
|
|
3863
|
+
files[job.path] = {
|
|
3864
|
+
type: "text",
|
|
3865
|
+
content: job.content
|
|
3866
|
+
};
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
return files;
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3627
3872
|
async function planProject(input) {
|
|
3628
3873
|
const planInput = isProjectPlanInput(input) ? input : resolveProjectPlanInput(input);
|
|
3629
3874
|
return createProjectPlan(await resolveProjectFacts(planInput));
|
|
@@ -3902,8 +4147,13 @@ function createProjectPlan(planInput) {
|
|
|
3902
4147
|
platforms: planInput.aiAgents.config.platforms
|
|
3903
4148
|
});
|
|
3904
4149
|
}
|
|
4150
|
+
const jobs = Object.entries(files).map(([path, file]) => ({
|
|
4151
|
+
type: "write-file",
|
|
4152
|
+
path,
|
|
4153
|
+
file
|
|
4154
|
+
}));
|
|
3905
4155
|
return {
|
|
3906
|
-
files,
|
|
4156
|
+
files: materializeJobs(jobs),
|
|
3907
4157
|
dependencies,
|
|
3908
4158
|
devDependencies,
|
|
3909
4159
|
peerDependencies,
|
|
@@ -3931,8 +4181,13 @@ async function planWorkspace(input) {
|
|
|
3931
4181
|
const planInput = isWorkspacePlanInput(input) ? input : resolveWorkspacePlanInput(input);
|
|
3932
4182
|
const resolvedInput = await resolveWorkspaceFacts(planInput);
|
|
3933
4183
|
const { files } = renderMonorepo(workspacePlanInputToMonorepoParams(resolvedInput));
|
|
4184
|
+
const jobs = Object.entries(files).map(([path, file]) => ({
|
|
4185
|
+
type: "write-file",
|
|
4186
|
+
path,
|
|
4187
|
+
file
|
|
4188
|
+
}));
|
|
3934
4189
|
return {
|
|
3935
|
-
files,
|
|
4190
|
+
files: materializeJobs(jobs),
|
|
3936
4191
|
dependencies: {},
|
|
3937
4192
|
devDependencies: {},
|
|
3938
4193
|
peerDependencies: {},
|
|
@@ -3948,11 +4203,22 @@ async function planWorkspace(input) {
|
|
|
3948
4203
|
exports.AI_PLATFORM_HINTS = AI_PLATFORM_HINTS;
|
|
3949
4204
|
exports.AI_PLATFORM_LABELS = AI_PLATFORM_LABELS;
|
|
3950
4205
|
exports.ALL_AI_PLATFORMS = ALL_AI_PLATFORMS;
|
|
4206
|
+
exports.DEFAULT_MINIMUM_RELEASE_AGE_MINUTES = DEFAULT_MINIMUM_RELEASE_AGE_MINUTES;
|
|
4207
|
+
exports.assignResolvedPackageVersion = assignResolvedPackageVersion;
|
|
4208
|
+
exports.clearConfig = clearConfig;
|
|
4209
|
+
exports.compareNumericSemver = compareNumericSemver;
|
|
3951
4210
|
exports.detectTooling = detectTooling;
|
|
4211
|
+
exports.formatEngine = formatEngine;
|
|
4212
|
+
exports.formatNodeTypesVersion = formatNodeTypesVersion;
|
|
4213
|
+
exports.formatPackageManager = formatPackageManager;
|
|
3952
4214
|
exports.formatResolvedPackageVersion = formatResolvedPackageVersion;
|
|
3953
4215
|
exports.generateRandomName = generateRandomName;
|
|
4216
|
+
exports.getAiPlatforms = getAiPlatforms;
|
|
3954
4217
|
exports.getBaseTemplate = getBaseTemplate;
|
|
4218
|
+
exports.getConfigPath = getConfigPath;
|
|
4219
|
+
exports.getConfigStrategy = getConfigStrategy;
|
|
3955
4220
|
exports.getEngineName = getEngineName;
|
|
4221
|
+
exports.getEngineSpec = getEngineSpec;
|
|
3956
4222
|
exports.getLanguageFromTemplate = getLanguageFromTemplate;
|
|
3957
4223
|
exports.getLatestNodeVersion = getLatestNodeVersion;
|
|
3958
4224
|
exports.getLatestNpmCliVersion = getLatestNpmCliVersion;
|
|
@@ -3961,13 +4227,21 @@ exports.getLatestNpmMajorVersionAtOrBelow = getLatestNpmMajorVersionAtOrBelow;
|
|
|
3961
4227
|
exports.getLatestNpmVersion = getLatestNpmVersion;
|
|
3962
4228
|
exports.getLatestPnpmVersion = getLatestPnpmVersion;
|
|
3963
4229
|
exports.getLatestYarnVersion = getLatestYarnVersion;
|
|
4230
|
+
exports.getPackageDirectoryName = getPackageDirectoryName;
|
|
4231
|
+
exports.getPackageFallbackVersion = getPackageFallbackVersion;
|
|
3964
4232
|
exports.getPackageManagerName = getPackageManagerName;
|
|
4233
|
+
exports.getPackageManagerProfile = getPackageManagerProfile;
|
|
4234
|
+
exports.getPackageManagerSpec = getPackageManagerSpec;
|
|
3965
4235
|
exports.getResolvedPackageVersion = getResolvedPackageVersion;
|
|
4236
|
+
exports.getSemverMajor = getSemverMajor;
|
|
4237
|
+
exports.getSemverMajorString = getSemverMajorString;
|
|
4238
|
+
exports.isPackageManagerName = isPackageManagerName;
|
|
4239
|
+
exports.materializeJobs = materializeJobs;
|
|
3966
4240
|
exports.merge = merge;
|
|
3967
4241
|
exports.mergePackageJsonScripts = mergePackageJsonScripts;
|
|
3968
4242
|
exports.packageJsonScripts = packageJsonScripts;
|
|
3969
4243
|
exports.parseEngine = parseEngine;
|
|
3970
|
-
exports.
|
|
4244
|
+
exports.parsePackageManagerSpec = parsePackageManagerSpec;
|
|
3971
4245
|
exports.parseWorkspaceYamlContent = parseWorkspaceYamlContent;
|
|
3972
4246
|
exports.planProject = planProject;
|
|
3973
4247
|
exports.planWorkspace = planWorkspace;
|
|
@@ -3979,17 +4253,28 @@ exports.renderGitignore = renderGitignore;
|
|
|
3979
4253
|
exports.renderOxfmtConfigPackage = renderOxfmtConfigPackage;
|
|
3980
4254
|
exports.renderOxlintConfig = renderOxlintConfig;
|
|
3981
4255
|
exports.renderOxlintConfigPackage = renderOxlintConfigPackage;
|
|
4256
|
+
exports.renderPnpmWorkspaceConfig = renderPnpmWorkspaceConfig;
|
|
3982
4257
|
exports.renderPrettierConfigPackage = renderPrettierConfigPackage;
|
|
3983
4258
|
exports.renderTypescriptConfigPackage = renderTypescriptConfigPackage;
|
|
3984
4259
|
exports.renderViteConfig = renderViteConfig;
|
|
3985
4260
|
exports.renderVscodeFiles = renderVscodeFiles;
|
|
3986
4261
|
exports.renderVscodeFiles$1 = renderVscodeFiles$1;
|
|
3987
4262
|
exports.resolveDefaultPackageJsonScripts = resolveDefaultPackageJsonScripts;
|
|
4263
|
+
exports.resolveEngine = resolveEngine;
|
|
3988
4264
|
exports.resolveMonorepoRootPackageVersions = resolveMonorepoRootPackageVersions;
|
|
4265
|
+
exports.resolvePackageManager = resolvePackageManager;
|
|
4266
|
+
exports.resolvePackageManagerProfile = resolvePackageManagerProfile;
|
|
4267
|
+
exports.resolvePackageVersions = resolvePackageVersions;
|
|
4268
|
+
exports.resolveProjectFacts = resolveProjectFacts;
|
|
4269
|
+
exports.resolveProjectPackageVersions = resolveProjectPackageVersions;
|
|
3989
4270
|
exports.resolveProjectPlanInput = resolveProjectPlanInput;
|
|
4271
|
+
exports.resolveWorkspaceFacts = resolveWorkspaceFacts;
|
|
3990
4272
|
exports.resolveWorkspacePlanInput = resolveWorkspacePlanInput;
|
|
4273
|
+
exports.setAiPlatforms = setAiPlatforms;
|
|
4274
|
+
exports.setConfigStrategy = setConfigStrategy;
|
|
3991
4275
|
exports.shouldEnableReactCompiler = shouldEnableReactCompiler;
|
|
3992
4276
|
exports.toPrettierIgnoreContent = toPrettierIgnoreContent;
|
|
3993
4277
|
exports.unique = unique;
|
|
3994
4278
|
exports.validatePackageName = validatePackageName;
|
|
4279
|
+
exports.validateWorkspace = validateWorkspace;
|
|
3995
4280
|
exports.workspacePlanInputToMonorepoParams = workspacePlanInputToMonorepoParams;
|