create-template-project 1.0.0 → 1.1.2
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/README.md +3 -5
- package/dist/config/dependencies.json +22 -18
- package/dist/index.js +92 -65
- package/dist/templates/base/files/.release-it.json +23 -0
- package/dist/templates/base/files/AGENTS.md +79 -2
- package/dist/templates/base/files/CONTRIBUTING.md +18 -7
- package/dist/templates/base/files/_oxc.config.ts +4 -1
- package/dist/templates/base/files/package.json +3 -0
- package/package.json +19 -16
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ pnpm dlx create-template-project interactive
|
|
|
27
27
|
- **Seed File Protection:** Files in `src/`, all `*.md` files, and other core files are skipped to protect your application logic and custom documentation.
|
|
28
28
|
- **Tooling Sync:** Keeps your project's boilerplate (linting, CI, configs, scripts) up-to-date with the latest template versions.
|
|
29
29
|
- **No-Build Option:** Supports creating simple projects without a build step (strips Vite).
|
|
30
|
-
- **GitHub Integration:** Automatically initializes a Git repository and can create a GitHub repository using the `gh` CLI.
|
|
30
|
+
- **GitHub Integration:** Automatically initializes a Git repository and can create a GitHub repository (including initial commit and push) using the `gh` CLI.
|
|
31
31
|
- **CI Ready:** Generates GitHub Actions workflows for automated testing and linting.
|
|
32
32
|
|
|
33
33
|
## Installation
|
|
@@ -89,9 +89,8 @@ create-template-project update --template cli
|
|
|
89
89
|
- `-a, --author <author>`: Author name (defaults to 'git config user.name')
|
|
90
90
|
- `--github-username <username>`: GitHub username (defaults to 'git config github.user')
|
|
91
91
|
- `-p, --package-manager <pm>`: Package manager (`npm`, `pnpm`, `yarn`) (defaults to `pnpm`)
|
|
92
|
-
- `--create-github-repository`: Create GitHub
|
|
92
|
+
- `--create-github-repository`: Create GitHub repository and push initial commit (requires `gh` CLI authenticated)
|
|
93
93
|
- `--path <path>`: Output directory (mandatory)
|
|
94
|
-
- `--install-dependencies`: Install dependencies after scaffolding
|
|
95
94
|
- `--build`: Run the CI script (lint, build, test) after scaffolding
|
|
96
95
|
- `--no-progress`: Do not show progress indicators
|
|
97
96
|
|
|
@@ -103,9 +102,8 @@ create-template-project update --template cli
|
|
|
103
102
|
- `-a, --author <author>`: Author name (defaults to 'git config user.name')
|
|
104
103
|
- `--github-username <username>`: GitHub username (defaults to 'git config github.user')
|
|
105
104
|
- `-p, --package-manager <pm>`: Package manager (`npm`, `pnpm`, `yarn`) (defaults to `pnpm`)
|
|
106
|
-
- `--create-github-repository`: Create GitHub
|
|
105
|
+
- `--create-github-repository`: Create GitHub repository and push initial commit (requires `gh` CLI authenticated)
|
|
107
106
|
- `-d, --directory <path>`: Output directory (defaults to `.`)
|
|
108
|
-
- `--install-dependencies`: Install dependencies after updating
|
|
109
107
|
- `--build`: Run the CI script (lint, build, test) after updating
|
|
110
108
|
- `--dev`: Run the dev server after updating
|
|
111
109
|
- `--open`: Open the browser after updating
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
3
|
"vite": {
|
|
4
|
-
"version": "8.0.
|
|
4
|
+
"version": "8.0.3",
|
|
5
5
|
"description": "Native-ESM powered web dev build tool"
|
|
6
6
|
},
|
|
7
7
|
"@vitejs/plugin-react": {
|
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
"description": "The default Vite plugin for React projects."
|
|
10
10
|
},
|
|
11
11
|
"@vitest/browser": {
|
|
12
|
-
"version": "4.1.
|
|
12
|
+
"version": "4.1.2",
|
|
13
13
|
"description": "Run Vitest in the browser."
|
|
14
14
|
},
|
|
15
15
|
"@vitest/browser-playwright": {
|
|
16
|
-
"version": "4.1.
|
|
16
|
+
"version": "4.1.2",
|
|
17
17
|
"description": "Playwright provider for Vitest browser mode."
|
|
18
18
|
},
|
|
19
19
|
"playwright": {
|
|
20
|
-
"version": "1.
|
|
20
|
+
"version": "1.59.1",
|
|
21
21
|
"description": "Framework for Web-browser automation."
|
|
22
22
|
},
|
|
23
23
|
"debug": {
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
"description": "TypeScript definitions for debug."
|
|
38
38
|
},
|
|
39
39
|
"@types/node": {
|
|
40
|
-
"version": "25.5.
|
|
40
|
+
"version": "25.5.2",
|
|
41
41
|
"description": "TypeScript definitions for Node.js."
|
|
42
42
|
},
|
|
43
43
|
"@vitest/coverage-v8": {
|
|
44
|
-
"version": "4.1.
|
|
44
|
+
"version": "4.1.2",
|
|
45
45
|
"description": "V8 coverage provider for Vitest."
|
|
46
46
|
},
|
|
47
47
|
"conventional-changelog": {
|
|
@@ -53,23 +53,23 @@
|
|
|
53
53
|
"description": "Modern native git hooks made easy."
|
|
54
54
|
},
|
|
55
55
|
"oxlint": {
|
|
56
|
-
"version": "1.
|
|
56
|
+
"version": "1.58.0",
|
|
57
57
|
"description": "A JavaScript linter written in Rust."
|
|
58
58
|
},
|
|
59
59
|
"oxlint-tsgolint": {
|
|
60
|
-
"version": "0.
|
|
60
|
+
"version": "0.19.0",
|
|
61
61
|
"description": "TypeScript-specific rules for oxlint."
|
|
62
62
|
},
|
|
63
63
|
"oxfmt": {
|
|
64
|
-
"version": "0.
|
|
64
|
+
"version": "0.43.0",
|
|
65
65
|
"description": "High performance JavaScript / TypeScript formatter."
|
|
66
66
|
},
|
|
67
67
|
"typescript": {
|
|
68
|
-
"version": "
|
|
68
|
+
"version": "6.0.2",
|
|
69
69
|
"description": "A superset of JavaScript that compiles to clean JavaScript output."
|
|
70
70
|
},
|
|
71
71
|
"vitest": {
|
|
72
|
-
"version": "4.1.
|
|
72
|
+
"version": "4.1.2",
|
|
73
73
|
"description": "A Vite-native unit test framework."
|
|
74
74
|
},
|
|
75
75
|
"commander": {
|
|
@@ -125,23 +125,23 @@
|
|
|
125
125
|
"description": "TypeScript definitions for React DOM."
|
|
126
126
|
},
|
|
127
127
|
"@playwright/test": {
|
|
128
|
-
"version": "1.
|
|
128
|
+
"version": "1.59.1",
|
|
129
129
|
"description": "End-to-end testing framework."
|
|
130
130
|
},
|
|
131
131
|
"@trpc/server": {
|
|
132
|
-
"version": "11.
|
|
132
|
+
"version": "11.16.0",
|
|
133
133
|
"description": "tRPC server library."
|
|
134
134
|
},
|
|
135
135
|
"@trpc/client": {
|
|
136
|
-
"version": "11.
|
|
136
|
+
"version": "11.16.0",
|
|
137
137
|
"description": "tRPC client library."
|
|
138
138
|
},
|
|
139
139
|
"@trpc/react-query": {
|
|
140
|
-
"version": "11.
|
|
140
|
+
"version": "11.16.0",
|
|
141
141
|
"description": "tRPC integration for React Query."
|
|
142
142
|
},
|
|
143
143
|
"@tanstack/react-query": {
|
|
144
|
-
"version": "5.
|
|
144
|
+
"version": "5.96.2",
|
|
145
145
|
"description": "Powerful asynchronous state management for TS/JS."
|
|
146
146
|
},
|
|
147
147
|
"zod": {
|
|
@@ -149,9 +149,13 @@
|
|
|
149
149
|
"description": "TypeScript-first schema validation with static type inference."
|
|
150
150
|
},
|
|
151
151
|
"react-router-dom": {
|
|
152
|
-
"version": "7.
|
|
152
|
+
"version": "7.14.0",
|
|
153
153
|
"description": "Declarative routing for React web applications."
|
|
154
154
|
},
|
|
155
|
+
"release-it": {
|
|
156
|
+
"version": "19.2.4",
|
|
157
|
+
"description": "Interactive release-tool for Git repositories."
|
|
158
|
+
},
|
|
155
159
|
"cors": {
|
|
156
160
|
"version": "2.8.6",
|
|
157
161
|
"description": "Node.js CORS middleware."
|
|
@@ -165,7 +169,7 @@
|
|
|
165
169
|
"description": "ESLint plugin for finding regexp mistakes and style guide violations."
|
|
166
170
|
},
|
|
167
171
|
"vitest-browser-react": {
|
|
168
|
-
"version": "2.
|
|
172
|
+
"version": "2.2.0",
|
|
169
173
|
"description": "Native React testing utilities for Vitest browser mode."
|
|
170
174
|
}
|
|
171
175
|
}
|
package/dist/index.js
CHANGED
|
@@ -32,7 +32,6 @@ var ProjectOptionsSchema = z.object({
|
|
|
32
32
|
createGithubRepository: z.boolean().optional().default(false),
|
|
33
33
|
directory: z.string(),
|
|
34
34
|
update: z.boolean().optional().default(false),
|
|
35
|
-
installDependencies: z.boolean().optional().default(false),
|
|
36
35
|
build: z.boolean().optional().default(false),
|
|
37
36
|
progress: z.boolean().optional().default(true)
|
|
38
37
|
});
|
|
@@ -258,6 +257,10 @@ var getBaseTemplate = (_opts) => {
|
|
|
258
257
|
name: "conventional-changelog",
|
|
259
258
|
description: "Automated release notes."
|
|
260
259
|
},
|
|
260
|
+
{
|
|
261
|
+
name: "release-it",
|
|
262
|
+
description: "Automated release workflow."
|
|
263
|
+
},
|
|
261
264
|
{
|
|
262
265
|
name: "debug",
|
|
263
266
|
description: "Structured logging for debugging."
|
|
@@ -268,7 +271,10 @@ var getBaseTemplate = (_opts) => {
|
|
|
268
271
|
}
|
|
269
272
|
],
|
|
270
273
|
dependencies: { zod: "zod" },
|
|
271
|
-
devDependencies: {
|
|
274
|
+
devDependencies: {
|
|
275
|
+
"eslint-plugin-regexp": "",
|
|
276
|
+
"release-it": ""
|
|
277
|
+
},
|
|
272
278
|
scripts: {},
|
|
273
279
|
files: [],
|
|
274
280
|
templateDir: getTemplateDir(__dirname$5, "base")
|
|
@@ -497,7 +503,6 @@ var MOCK_OPTS = {
|
|
|
497
503
|
directory: ".",
|
|
498
504
|
packageManager: "npm",
|
|
499
505
|
update: false,
|
|
500
|
-
installDependencies: false,
|
|
501
506
|
build: false,
|
|
502
507
|
progress: true,
|
|
503
508
|
createGithubRepository: false
|
|
@@ -540,6 +545,17 @@ var getAllTemplatesInfo = () => {
|
|
|
540
545
|
//#endregion
|
|
541
546
|
//#region src/cli.ts
|
|
542
547
|
var pathExists$1 = (p) => fs.access(p).then(() => true).catch(() => false);
|
|
548
|
+
var stripQuotes = (str) => {
|
|
549
|
+
if (typeof str !== "string") return str;
|
|
550
|
+
let result = str.trim();
|
|
551
|
+
while (result.length >= 2) {
|
|
552
|
+
const first = result[0];
|
|
553
|
+
const last = result[result.length - 1];
|
|
554
|
+
if (first === "\"" && last === "\"" || first === "'" && last === "'") result = result.substring(1, result.length - 1).trim();
|
|
555
|
+
else break;
|
|
556
|
+
}
|
|
557
|
+
return result;
|
|
558
|
+
};
|
|
543
559
|
var getDefaultAuthor = async () => {
|
|
544
560
|
try {
|
|
545
561
|
const { stdout } = await execa("git", ["config", "user.name"]);
|
|
@@ -609,7 +625,7 @@ Templates:
|
|
|
609
625
|
p.outro("Use \"create\" to scaffold a new project.");
|
|
610
626
|
process.exit(0);
|
|
611
627
|
});
|
|
612
|
-
program.command("create").description("Create a new project from a template").option("-t, --template <type>", "Template type (cli, web-vanilla, web-app, web-fullstack)").option("-n, --name <name>", "Project name").option("--description <description>", "Project description").option("-k, --keywords <keywords>", "Project keywords (comma separated)").option("-a, --author <author>", "Author name (defaults to 'git config user.name')").option("--github-username <username>", "GitHub username (defaults to 'git config github.user')").option("-p, --package-manager <pm>", "Package manager (npm, pnpm, yarn)", "pnpm").option("--create-github-repository", "Create GitHub
|
|
628
|
+
program.command("create").description("Create a new project from a template").option("-t, --template <type>", "Template type (cli, web-vanilla, web-app, web-fullstack)").option("-n, --name <name>", "Project name").option("--description <description>", "Project description").option("-k, --keywords <keywords>", "Project keywords (comma separated)").option("-a, --author <author>", "Author name (defaults to 'git config user.name')").option("--github-username <username>", "GitHub username (defaults to 'git config github.user')").option("-p, --package-manager <pm>", "Package manager (npm, pnpm, yarn)", "pnpm").option("--create-github-repository", "Create GitHub repository and push initial commit").requiredOption("--path <path>", "Output directory").option("--build", "Run the CI script (lint, build, test) after scaffolding", false).option("--no-progress", "Do not show progress indicators").action(async (opts) => {
|
|
613
629
|
debug$2("Executing \"create\" command with options: %O", opts);
|
|
614
630
|
commandResult = {
|
|
615
631
|
...opts,
|
|
@@ -637,7 +653,7 @@ Restrictions & Behavior:
|
|
|
637
653
|
- package.json: Dependencies and scripts are merged. Existing versions are preserved unless they are missing.
|
|
638
654
|
- Merging: For non-seed files, the tool attempts to merge template changes. If a conflict occurs, it will be marked with standard git conflict markers.
|
|
639
655
|
- Confirmation: The command will always show a summary of proposed changes (ADD, MODIFY) and ask for your confirmation before applying them.
|
|
640
|
-
`).option("-t, --template <type>", "Template type (cli, web-vanilla, web-app, web-fullstack)").option("--description <description>", "Project description").option("-k, --keywords <keywords>", "Project keywords (comma separated)").option("-a, --author <author>", "Author name (defaults to 'git config user.name')").option("--github-username <username>", "GitHub username (defaults to 'git config github.user')").option("-p, --package-manager <pm>", "Package manager (npm, pnpm, yarn)", "pnpm").option("--create-github-repository", "Create GitHub
|
|
656
|
+
`).option("-t, --template <type>", "Template type (cli, web-vanilla, web-app, web-fullstack)").option("--description <description>", "Project description").option("-k, --keywords <keywords>", "Project keywords (comma separated)").option("-a, --author <author>", "Author name (defaults to 'git config user.name')").option("--github-username <username>", "GitHub username (defaults to 'git config github.user')").option("-p, --package-manager <pm>", "Package manager (npm, pnpm, yarn)", "pnpm").option("--create-github-repository", "Create GitHub repository and push initial commit").option("-d, --directory <path>", "Output directory", ".").option("--build", "Run the CI script (lint, build, test) after updating", false).option("--dev", "Run the dev server after scaffolding", false).option("--open", "Open the browser after scaffolding", false).option("--no-progress", "Do not show progress indicators").action(async (opts) => {
|
|
641
657
|
debug$2("Executing \"update\" command with options: %O", opts);
|
|
642
658
|
const directory = path.resolve(opts.directory);
|
|
643
659
|
const pkgPath = path.join(directory, "package.json");
|
|
@@ -834,29 +850,16 @@ Restrictions & Behavior:
|
|
|
834
850
|
process.exit(0);
|
|
835
851
|
}
|
|
836
852
|
}
|
|
837
|
-
const
|
|
838
|
-
message: "Should we
|
|
853
|
+
const build = await p.confirm({
|
|
854
|
+
message: "Should we run the CI script (lint, build, test)?",
|
|
839
855
|
initialValue: true
|
|
840
856
|
});
|
|
841
|
-
if (p.isCancel(
|
|
857
|
+
if (p.isCancel(build)) {
|
|
842
858
|
p.cancel("Operation cancelled.");
|
|
843
859
|
process.exit(0);
|
|
844
860
|
}
|
|
845
|
-
const installDependencies = installDependenciesRes;
|
|
846
|
-
let build = false;
|
|
847
|
-
if (installDependencies) {
|
|
848
|
-
const res = await p.confirm({
|
|
849
|
-
message: "Should we run the CI script (lint, build, test)?",
|
|
850
|
-
initialValue: true
|
|
851
|
-
});
|
|
852
|
-
if (p.isCancel(res)) {
|
|
853
|
-
p.cancel("Operation cancelled.");
|
|
854
|
-
process.exit(0);
|
|
855
|
-
}
|
|
856
|
-
build = res;
|
|
857
|
-
}
|
|
858
861
|
const createGithubRepositoryRes = await p.confirm({
|
|
859
|
-
message: "
|
|
862
|
+
message: "Create GitHub repository and push initial commit?",
|
|
860
863
|
initialValue: false
|
|
861
864
|
});
|
|
862
865
|
if (p.isCancel(createGithubRepositoryRes)) {
|
|
@@ -874,7 +877,6 @@ Restrictions & Behavior:
|
|
|
874
877
|
createGithubRepository: createGithubRepositoryRes,
|
|
875
878
|
directory: projectDir,
|
|
876
879
|
update,
|
|
877
|
-
installDependencies,
|
|
878
880
|
build,
|
|
879
881
|
progress: true
|
|
880
882
|
};
|
|
@@ -896,6 +898,13 @@ Restrictions & Behavior:
|
|
|
896
898
|
p.cancel("Unknown command or missing options.");
|
|
897
899
|
process.exit(1);
|
|
898
900
|
}
|
|
901
|
+
if (commandResult.template) commandResult.template = stripQuotes(commandResult.template);
|
|
902
|
+
if (commandResult.projectName) commandResult.projectName = stripQuotes(commandResult.projectName);
|
|
903
|
+
if (commandResult.description) commandResult.description = stripQuotes(commandResult.description);
|
|
904
|
+
if (commandResult.keywords) commandResult.keywords = stripQuotes(commandResult.keywords);
|
|
905
|
+
if (commandResult.author) commandResult.author = stripQuotes(commandResult.author);
|
|
906
|
+
if (commandResult.githubUsername) commandResult.githubUsername = stripQuotes(commandResult.githubUsername);
|
|
907
|
+
if (commandResult.packageManager) commandResult.packageManager = stripQuotes(commandResult.packageManager);
|
|
899
908
|
debug$2("Validating command result with Zod");
|
|
900
909
|
const validationResult = ProjectOptionsSchema.safeParse(commandResult);
|
|
901
910
|
if (!validationResult.success) {
|
|
@@ -909,7 +918,6 @@ Restrictions & Behavior:
|
|
|
909
918
|
p.cancel(`Directory "${projectDir}" already exists. Use the "update" command to update.`);
|
|
910
919
|
process.exit(1);
|
|
911
920
|
}
|
|
912
|
-
if (commandResult.build) commandResult.installDependencies = true;
|
|
913
921
|
return commandResult;
|
|
914
922
|
};
|
|
915
923
|
//#endregion
|
|
@@ -993,7 +1001,7 @@ var generateProject = async (opts) => {
|
|
|
993
1001
|
description: config.description
|
|
994
1002
|
});
|
|
995
1003
|
} else {
|
|
996
|
-
log.warn(`Dependency "${dep}" not found in
|
|
1004
|
+
log.warn(`Dependency "${dep}" not found in central configuration. Using empty version.`);
|
|
997
1005
|
debug$1(`Dependency "${dep}" missing in config`);
|
|
998
1006
|
}
|
|
999
1007
|
}
|
|
@@ -1001,6 +1009,7 @@ var generateProject = async (opts) => {
|
|
|
1001
1009
|
let finalPkg = {
|
|
1002
1010
|
name: projectName,
|
|
1003
1011
|
version: "0.1.0",
|
|
1012
|
+
private: true,
|
|
1004
1013
|
description: opts.description || "TODO: Add project description",
|
|
1005
1014
|
keywords: opts.keywords ? opts.keywords.split(",").map((k) => k.trim()) : ["TODO: Add keywords"],
|
|
1006
1015
|
homepage: `https://github.com/${githubUsername}/${projectName}#readme`,
|
|
@@ -1273,7 +1282,7 @@ var generateProject = async (opts) => {
|
|
|
1273
1282
|
githubSkipped: !opts.createGithubRepository || isUpdate,
|
|
1274
1283
|
githubError: "",
|
|
1275
1284
|
depsInstalled: false,
|
|
1276
|
-
depsSkipped: !opts.
|
|
1285
|
+
depsSkipped: !opts.build,
|
|
1277
1286
|
ciRun: false,
|
|
1278
1287
|
ciSkipped: !opts.build || !finalPkg.scripts.ci
|
|
1279
1288
|
};
|
|
@@ -1281,13 +1290,13 @@ var generateProject = async (opts) => {
|
|
|
1281
1290
|
if (!await pathExists(path.join(projectDir, ".git"))) {
|
|
1282
1291
|
debug$1("Initializing Git repository");
|
|
1283
1292
|
try {
|
|
1284
|
-
debug$1("Executing: git init");
|
|
1285
|
-
await execa("git", ["init"], {
|
|
1293
|
+
debug$1("Executing: git init --initial-branch=main");
|
|
1294
|
+
await execa("git", ["init", "--initial-branch=main"], {
|
|
1286
1295
|
cwd: projectDir,
|
|
1287
1296
|
stdio,
|
|
1288
1297
|
preferLocal: true
|
|
1289
1298
|
});
|
|
1290
|
-
log.success("Initialized Git repository (
|
|
1299
|
+
log.success("Initialized Git repository (main branch).");
|
|
1291
1300
|
states.gitInitialized = true;
|
|
1292
1301
|
} catch (e) {
|
|
1293
1302
|
debug$1("Failed to initialize Git: %O", e);
|
|
@@ -1295,32 +1304,7 @@ var generateProject = async (opts) => {
|
|
|
1295
1304
|
log.error(`Failed to initialize Git: ${e.message}${detail}`);
|
|
1296
1305
|
}
|
|
1297
1306
|
} else states.gitInitialized = true;
|
|
1298
|
-
if (opts.
|
|
1299
|
-
debug$1("Creating GitHub repository");
|
|
1300
|
-
try {
|
|
1301
|
-
debug$1("Executing: gh repo create %s --public --source=. --remote=origin", projectName);
|
|
1302
|
-
await execa("gh", [
|
|
1303
|
-
"repo",
|
|
1304
|
-
"create",
|
|
1305
|
-
projectName,
|
|
1306
|
-
"--public",
|
|
1307
|
-
"--source=.",
|
|
1308
|
-
"--remote=origin"
|
|
1309
|
-
], {
|
|
1310
|
-
cwd: projectDir,
|
|
1311
|
-
stdio,
|
|
1312
|
-
preferLocal: true
|
|
1313
|
-
});
|
|
1314
|
-
log.success("Created GitHub repository (gh repo create).");
|
|
1315
|
-
states.githubCreated = true;
|
|
1316
|
-
} catch (e) {
|
|
1317
|
-
debug$1("Failed to create GitHub repository: %O", e);
|
|
1318
|
-
const detail = e.stdout || e.stderr ? `\n\nOutput:\n${e.stdout}\n${e.stderr}` : "";
|
|
1319
|
-
log.warn(`Failed to create GitHub repository: ${e.message}${detail}\nEnsure "gh" CLI is installed and authenticated.`);
|
|
1320
|
-
states.githubError = e.message;
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
if (opts.installDependencies) {
|
|
1307
|
+
if (opts.build) {
|
|
1324
1308
|
debug$1("Installing dependencies using %s", pm);
|
|
1325
1309
|
const s = spinner();
|
|
1326
1310
|
s.start(`Installing dependencies using ${pm}...`);
|
|
@@ -1379,6 +1363,51 @@ var generateProject = async (opts) => {
|
|
|
1379
1363
|
throw new Error(`Failed to run CI script: ${e.message}${detail}`);
|
|
1380
1364
|
}
|
|
1381
1365
|
}
|
|
1366
|
+
if (opts.createGithubRepository && !isUpdate) {
|
|
1367
|
+
debug$1("Creating and pushing GitHub repository");
|
|
1368
|
+
const s = spinner();
|
|
1369
|
+
s.start("Creating and pushing GitHub repository...");
|
|
1370
|
+
try {
|
|
1371
|
+
debug$1("Executing: git add .");
|
|
1372
|
+
await execa("git", ["add", "."], {
|
|
1373
|
+
cwd: projectDir,
|
|
1374
|
+
stdio,
|
|
1375
|
+
preferLocal: true
|
|
1376
|
+
});
|
|
1377
|
+
debug$1("Executing: git commit -m \"chore: initial scaffold\"");
|
|
1378
|
+
await execa("git", [
|
|
1379
|
+
"commit",
|
|
1380
|
+
"-m",
|
|
1381
|
+
"chore: initial scaffold"
|
|
1382
|
+
], {
|
|
1383
|
+
cwd: projectDir,
|
|
1384
|
+
stdio,
|
|
1385
|
+
preferLocal: true
|
|
1386
|
+
});
|
|
1387
|
+
debug$1("Executing: gh repo create %s --public --source=. --remote=origin --push", projectName);
|
|
1388
|
+
await execa("gh", [
|
|
1389
|
+
"repo",
|
|
1390
|
+
"create",
|
|
1391
|
+
projectName,
|
|
1392
|
+
"--public",
|
|
1393
|
+
"--source=.",
|
|
1394
|
+
"--remote=origin",
|
|
1395
|
+
"--push"
|
|
1396
|
+
], {
|
|
1397
|
+
cwd: projectDir,
|
|
1398
|
+
stdio,
|
|
1399
|
+
preferLocal: true
|
|
1400
|
+
});
|
|
1401
|
+
s.stop(`\x1b[1G\x1b[2K\x1b[32m◆\x1b[39m Created GitHub repository and pushed initial commit.`);
|
|
1402
|
+
states.githubCreated = true;
|
|
1403
|
+
} catch (e) {
|
|
1404
|
+
debug$1("Failed to create/push GitHub repository: %O", e);
|
|
1405
|
+
s.stop("Failed to create/push GitHub repository.");
|
|
1406
|
+
const detail = e.stdout || e.stderr ? `\n\nOutput:\n${e.stdout}\n${e.stderr}` : "";
|
|
1407
|
+
log.warn(`Failed to create/push GitHub repository: ${e.message}${detail}\nEnsure "gh" CLI is installed and authenticated.`);
|
|
1408
|
+
states.githubError = e.message;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1382
1411
|
let hasErrors = false;
|
|
1383
1412
|
let hasWarnings = false;
|
|
1384
1413
|
const errorMessages = [];
|
|
@@ -1421,8 +1450,8 @@ async function generateGeneratedMd(projectDir, opts, pm, states, isUpdate, statu
|
|
|
1421
1450
|
`- [x] Scaffold project files and directories`,
|
|
1422
1451
|
`- [x] Configure \`package.json\` with appropriate dependencies`,
|
|
1423
1452
|
`- [${states.depsInstalled ? "x" : " "}] Install dependencies using \`${pm}\`${states.depsSkipped ? " *(Skipped)*" : ""}`,
|
|
1424
|
-
`- [${states.gitInitialized ? "x" : " "}] Initialize Git repository`,
|
|
1425
|
-
`- [${states.githubCreated ? "x" : " "}] Create GitHub repository${states.githubSkipped ? " *(Skipped)*" : states.githubError ? " *(Failed)*" : ""}`,
|
|
1453
|
+
`- [${states.gitInitialized ? "x" : " "}] Initialize Git repository (main branch)`,
|
|
1454
|
+
`- [${states.githubCreated ? "x" : " "}] Create and push GitHub repository${states.githubSkipped ? " *(Skipped)*" : states.githubError ? " *(Failed)*" : ""}`,
|
|
1426
1455
|
`- [${states.ciRun ? "x" : " "}] Run initial CI pipeline (lint, build, test)${states.ciSkipped ? " *(Skipped)*" : ""}`,
|
|
1427
1456
|
"",
|
|
1428
1457
|
...isUpdate ? [
|
|
@@ -1519,19 +1548,17 @@ async function generateGeneratedMd(projectDir, opts, pm, states, isUpdate, statu
|
|
|
1519
1548
|
"| `gh pr checkout <pr-number>` | Checkout a Pull Request branch locally |",
|
|
1520
1549
|
"| `gh issue create` | Create a new Issue |",
|
|
1521
1550
|
"| `gh issue list` | List all open Issues |",
|
|
1522
|
-
"| `gh repo delete <owner>/<repo> --
|
|
1551
|
+
"| `gh repo delete <owner>/<repo> --yes` | Dangerously delete a repository completely (use with caution!) |",
|
|
1523
1552
|
"",
|
|
1524
1553
|
"---",
|
|
1525
1554
|
"",
|
|
1526
1555
|
"## 🚀 Creating a Release",
|
|
1527
1556
|
"This project uses Conventional Commits and automated changelogs. To create a new release:",
|
|
1528
|
-
"1. **
|
|
1529
|
-
"
|
|
1530
|
-
"
|
|
1531
|
-
"
|
|
1532
|
-
"
|
|
1533
|
-
"6. **Create GitHub Release:** `gh release create v$(node -p 'require(\"./package.json\").version') --generate-notes`",
|
|
1534
|
-
"7. **Publish (if applicable):** `pnpm publish`",
|
|
1557
|
+
"1. **Run the release command:** `pnpm release`",
|
|
1558
|
+
"",
|
|
1559
|
+
"This single command will automatically run your CI suite, bump the version, generate a changelog, create a Git tag, push to GitHub, and create a GitHub release.",
|
|
1560
|
+
"",
|
|
1561
|
+
"**Note:** NPM publishing is disabled by default. See `CONTRIBUTING.md` for details on how to enable it.",
|
|
1535
1562
|
"",
|
|
1536
1563
|
"---",
|
|
1537
1564
|
"",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"npm": {
|
|
3
|
+
"publish": false
|
|
4
|
+
},
|
|
5
|
+
"git": {
|
|
6
|
+
"requireCleanWorkingDir": true,
|
|
7
|
+
"commit": true,
|
|
8
|
+
"commitMessage": "chore(release): ${version}",
|
|
9
|
+
"tag": true,
|
|
10
|
+
"tagName": "v${version}",
|
|
11
|
+
"push": true,
|
|
12
|
+
"pushArgs": ["--follow-tags"]
|
|
13
|
+
},
|
|
14
|
+
"github": {
|
|
15
|
+
"release": true,
|
|
16
|
+
"autoGenerate": true
|
|
17
|
+
},
|
|
18
|
+
"hooks": {
|
|
19
|
+
"before:init": "pnpm run ci",
|
|
20
|
+
"after:bump": "pnpm run create-changelog",
|
|
21
|
+
"before:git:commit": "git add CHANGELOG.md"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,9 +1,86 @@
|
|
|
1
1
|
# Agent Guidelines: {{projectName}}
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This document provides essential instructions for autonomous agents (like Cursor, GitHub Copilot, or CLI agents) working on the `{{projectName}}` repository.
|
|
4
|
+
|
|
5
|
+
## Build/Lint/Test
|
|
6
|
+
|
|
4
7
|
- `pnpm run ci`: Runs lint, build, and all tests.
|
|
5
8
|
- `pnpm run dev`: Starts the development server.
|
|
6
|
-
- `pnpm run test`: Runs unit tests
|
|
9
|
+
- `pnpm run test`: Runs unit tests.
|
|
7
10
|
- `pnpm run integration-test`: Runs integration tests.
|
|
8
11
|
- `pnpm exec vitest <file>`: Runs a specific test file.
|
|
9
12
|
- `pnpm run lint`: Lints and formats the codebase (oxlint + oxfmt).
|
|
13
|
+
|
|
14
|
+
## Project Overview
|
|
15
|
+
|
|
16
|
+
A modern project built with {{projectName}}, emphasizing type safety, performance, and best practices.
|
|
17
|
+
|
|
18
|
+
## Build, Lint, and Test Commands
|
|
19
|
+
|
|
20
|
+
### Core Commands
|
|
21
|
+
|
|
22
|
+
- **Install dependencies:** `pnpm install`
|
|
23
|
+
- **Build project:** `pnpm run build`
|
|
24
|
+
- **Lint code:** `pnpm run lint` (runs `tsc`, `oxlint`, and `oxfmt`)
|
|
25
|
+
- **Run all tests:** `pnpm run test` (uses `vitest` with coverage)
|
|
26
|
+
- **Run CI suite:** `pnpm run ci` (lint + build + test)
|
|
27
|
+
- **Run integration tests:** `pnpm run integration-test`
|
|
28
|
+
|
|
29
|
+
### Targeted Testing
|
|
30
|
+
|
|
31
|
+
- **Run a single test file:** `pnpm exec vitest src/index.test.ts`
|
|
32
|
+
- **Run tests matching a pattern:** `pnpm exec vitest -t "feature"`
|
|
33
|
+
- **Watch mode:** `pnpm exec vitest`
|
|
34
|
+
|
|
35
|
+
## Code Style & Conventions
|
|
36
|
+
|
|
37
|
+
### Language & Runtime
|
|
38
|
+
|
|
39
|
+
- **TypeScript:** Strict mode is mandatory. Use explicit types for function boundaries.
|
|
40
|
+
- **Node.js:** Targets >= 22.0.0.
|
|
41
|
+
- **ESM:** The project uses ES Modules (`"type": "module"` in `package.json`).
|
|
42
|
+
|
|
43
|
+
### Imports
|
|
44
|
+
|
|
45
|
+
- **Extensions:** Always use `.js` extensions in relative imports (e.g., `import { main } from './lib.js';`) to comply with ESM requirements in Node.js, even though source files are `.ts`.
|
|
46
|
+
- **Built-ins:** Use the `node:` prefix for built-in modules (e.g., `import path from 'node:path';`).
|
|
47
|
+
|
|
48
|
+
### Formatting
|
|
49
|
+
|
|
50
|
+
- **Tooling:** oxfmt is enforced via `pnpm run lint`.
|
|
51
|
+
- **Indentation:** Tabs are used for indentation.
|
|
52
|
+
- **Quotes:** Single quotes for strings, except when double quotes prevent escaping.
|
|
53
|
+
|
|
54
|
+
### Architecture & Types
|
|
55
|
+
|
|
56
|
+
- **Modularity:** Keep logic modularized.
|
|
57
|
+
- **Type Safety:** Use `zod` for runtime schema validation and `z.infer` for type definitions.
|
|
58
|
+
- **Immutability:** Prefer `readonly` and `const` where possible to ensure data integrity.
|
|
59
|
+
|
|
60
|
+
### Naming Conventions
|
|
61
|
+
|
|
62
|
+
- **Variables/Functions:** `camelCase`.
|
|
63
|
+
- **Constants:** `UPPER_SNAKE_CASE`.
|
|
64
|
+
- **Files:** `kebab-case.ts`.
|
|
65
|
+
|
|
66
|
+
### Error Handling
|
|
67
|
+
|
|
68
|
+
- **CLI Errors:** Throw descriptive errors.
|
|
69
|
+
- **Safety:** Always use `try...finally` or `using` (if applicable) to ensure resources like file handles or connections are closed.
|
|
70
|
+
- **Validation:** Validate all user inputs and CLI arguments using Zod schemas before processing.
|
|
71
|
+
|
|
72
|
+
## Mandatory Completion Protocol (Definition of Done)
|
|
73
|
+
|
|
74
|
+
No task involving code changes is considered complete until the agent provides the following "Evidence of Done" in its final response:
|
|
75
|
+
|
|
76
|
+
1. **CI Verification:** The agent MUST run `pnpm run ci` and include the full terminal output (showing `Found 0 warnings and 0 errors` and `Tests passed`).
|
|
77
|
+
2. **Test Coverage:** The agent MUST ensure that all new code is covered by tests and all existing tests pass.
|
|
78
|
+
|
|
79
|
+
**Failure to provide these logs means the task is INCOMPLETE.** The user is encouraged to reject any response that lacks this section.
|
|
80
|
+
|
|
81
|
+
## Git Workflow
|
|
82
|
+
|
|
83
|
+
- **Conventional Commits:** Adhere to the specification (e.g., `feat:`, `fix:`, `chore:`, `test:`).
|
|
84
|
+
- **Hooks:** Husky runs `pnpm run ci` on pre-commit. Do not bypass hooks.
|
|
85
|
+
- **Branches:** Use descriptive branch names like `feat/feature-name` or `fix/issue-description`.
|
|
86
|
+
|
|
@@ -21,11 +21,22 @@ We follow the **Conventional Commits** specification. This is **enforced** by `c
|
|
|
21
21
|
|
|
22
22
|
## Release Process
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
To release a new version:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
pnpm release -- patch # or minor / major
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This will automatically:
|
|
31
|
+
1. Run the CI suite (`pnpm run ci`).
|
|
32
|
+
2. Bump the version in `package.json`.
|
|
33
|
+
3. Update the `CHANGELOG.md`.
|
|
34
|
+
4. Commit, tag, and push the changes.
|
|
35
|
+
5. Create a GitHub release with auto-generated notes.
|
|
36
|
+
6. Publish to npm (if configured).
|
|
37
|
+
|
|
38
|
+
**Note:** NPM publishing is **disabled** by default for new projects. To enable it:
|
|
39
|
+
1. Set `"private": false` in `package.json`.
|
|
40
|
+
2. Set `"publish": true` in `.release-it.json`.
|
|
41
|
+
3. Ensure you have the necessary `NPM_TOKEN` configured.
|
|
31
42
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { defineConfig } from "oxlint";
|
|
2
2
|
import pluginRegexp from "eslint-plugin-regexp";
|
|
3
3
|
|
|
4
|
+
/** Filter out core ESLint rules bundled into eslint-plugin-regexp recommended config */
|
|
5
|
+
const regexpPluginRules = Object.fromEntries(Object.entries(pluginRegexp.configs.recommended.rules ?? {}).filter(([key]) => key.startsWith("regexp/")));
|
|
6
|
+
|
|
4
7
|
const commonIgnore = [
|
|
5
8
|
"**/.*",
|
|
6
9
|
"node_modules/**",
|
|
@@ -32,7 +35,7 @@ export const linter = defineConfig({
|
|
|
32
35
|
correctness: "error",
|
|
33
36
|
},
|
|
34
37
|
rules: {
|
|
35
|
-
...
|
|
38
|
+
...regexpPluginRules,
|
|
36
39
|
curly: ["error", "all"],
|
|
37
40
|
"typescript/no-unused-vars": [
|
|
38
41
|
"error",
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "{{projectName}}",
|
|
3
3
|
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
4
5
|
"type": "module",
|
|
5
6
|
"scripts": {
|
|
6
7
|
"lint": "tsc && oxlint --disable-nested-config src client server tests *.config.ts && npm run format:check",
|
|
7
8
|
"format": "oxfmt --write .",
|
|
8
9
|
"format:check": "oxfmt --check .",
|
|
9
10
|
"test": "vitest run --coverage",
|
|
11
|
+
"release": "release-it",
|
|
10
12
|
"ci": "npm run lint && npm run build && npm run test",
|
|
11
13
|
"create-changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
|
|
12
14
|
"prepare": "husky"
|
|
@@ -25,6 +27,7 @@
|
|
|
25
27
|
"oxlint": "",
|
|
26
28
|
"oxlint-tsgolint": "",
|
|
27
29
|
"oxfmt": "",
|
|
30
|
+
"release-it": "",
|
|
28
31
|
"eslint-plugin-regexp": "",
|
|
29
32
|
"typescript": "",
|
|
30
33
|
"vitest": ""
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-template-project",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"private": false,
|
|
4
5
|
"description": "An ultra-modular, type-safe Node.js CLI tool used to scaffold new project templates (CLI, Webpage, Webapp, Fullstack) with best-practice configurations pre-installed.",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"boilerplate",
|
|
@@ -54,17 +55,18 @@
|
|
|
54
55
|
"format": "oxfmt --write src scripts *.config.ts",
|
|
55
56
|
"format:check": "oxfmt --check src scripts *.config.ts",
|
|
56
57
|
"test": "vitest run --coverage --exclude '**/*.integration.*.test.ts'",
|
|
57
|
-
"integration-test:cli": "rimraf ./temp/cli && node ./dist/index.js create --package-manager=pnpm --build --debug --no-progress --template=cli --name=cli --author=\"Jon Doe\" --github-username=\"jon-doe\" --path=./temp/cli",
|
|
58
|
-
"integration-test:web-vanilla": "rimraf ./temp/web-vanilla && node ./dist/index.js create --package-manager=pnpm --build --debug --no-progress --template=web-vanilla --name=web-vanilla --author=\"Jon Doe\" --github-username=\"jon-doe\" --path=./temp/web-vanilla",
|
|
59
|
-
"integration-test:web-app": "rimraf ./temp/web-app && node ./dist/index.js create --package-manager=pnpm --build --debug --no-progress --template=web-app --name=web-app --author=\"Jon Doe\" --github-username=\"jon-doe\" --path=./temp/web-app",
|
|
60
|
-
"integration-test:web-fullstack": "rimraf ./temp/web-fullstack && node ./dist/index.js create --package-manager=pnpm --build --debug --no-progress --template=web-fullstack --name=web-fullstack --author=\"Jon Doe\" --github-username=\"jon-doe\" --path=./temp/web-fullstack",
|
|
58
|
+
"integration-test:cli": "rimraf --max-retries=3 ./temp/cli && node ./dist/index.js create --package-manager=pnpm --build --debug --no-progress --template=cli --name=cli --author=\"Jon Doe\" --github-username=\"jon-doe\" --path=./temp/cli",
|
|
59
|
+
"integration-test:web-vanilla": "rimraf --max-retries=3 ./temp/web-vanilla && node ./dist/index.js create --package-manager=pnpm --build --debug --no-progress --template=web-vanilla --name=web-vanilla --author=\"Jon Doe\" --github-username=\"jon-doe\" --path=./temp/web-vanilla",
|
|
60
|
+
"integration-test:web-app": "rimraf --max-retries=3 ./temp/web-app && node ./dist/index.js create --package-manager=pnpm --build --debug --no-progress --template=web-app --name=web-app --author=\"Jon Doe\" --github-username=\"jon-doe\" --path=./temp/web-app",
|
|
61
|
+
"integration-test:web-fullstack": "rimraf --max-retries=3 ./temp/web-fullstack && node ./dist/index.js create --package-manager=pnpm --build --debug --no-progress --template=web-fullstack --name=web-fullstack --author=\"Jon Doe\" --github-username=\"jon-doe\" --path=./temp/web-fullstack",
|
|
61
62
|
"integration-test": "pnpm run integration-test:cli && pnpm run integration-test:web-vanilla && pnpm run integration-test:web-app && pnpm run integration-test:web-fullstack",
|
|
62
63
|
"ci": "pnpm run lint && pnpm run build && pnpm run test",
|
|
63
64
|
"create-changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
|
|
64
|
-
"prepare": "husky"
|
|
65
|
+
"prepare": "husky",
|
|
66
|
+
"release": "release-it"
|
|
65
67
|
},
|
|
66
68
|
"dependencies": {
|
|
67
|
-
"@clack/prompts": "1.
|
|
69
|
+
"@clack/prompts": "1.2.0",
|
|
68
70
|
"commander": "14.0.3",
|
|
69
71
|
"debug": "4.4.3",
|
|
70
72
|
"execa": "9.6.1",
|
|
@@ -75,19 +77,20 @@
|
|
|
75
77
|
"@commitlint/config-conventional": "20.5.0",
|
|
76
78
|
"@types/cli-progress": "3.11.6",
|
|
77
79
|
"@types/debug": "4.1.13",
|
|
78
|
-
"@vitest/coverage-v8": "4.1.
|
|
80
|
+
"@vitest/coverage-v8": "4.1.2",
|
|
79
81
|
"conventional-changelog": "7.2.0",
|
|
80
|
-
"conventional-changelog-angular": "8.3.
|
|
82
|
+
"conventional-changelog-angular": "8.3.1",
|
|
81
83
|
"eslint-plugin-regexp": "3.1.0",
|
|
82
84
|
"husky": "9.1.7",
|
|
83
|
-
"oxfmt": "0.
|
|
84
|
-
"oxlint": "1.
|
|
85
|
-
"oxlint-tsgolint": "0.
|
|
86
|
-
"pnpm": "10.
|
|
85
|
+
"oxfmt": "0.43.0",
|
|
86
|
+
"oxlint": "1.58.0",
|
|
87
|
+
"oxlint-tsgolint": "0.19.0",
|
|
88
|
+
"pnpm": "10.33.0",
|
|
89
|
+
"release-it": "19.2.4",
|
|
87
90
|
"rimraf": "6.1.3",
|
|
88
|
-
"typescript": "
|
|
89
|
-
"vite": "8.0.
|
|
90
|
-
"vitest": "4.1.
|
|
91
|
+
"typescript": "6.0.2",
|
|
92
|
+
"vite": "8.0.3",
|
|
93
|
+
"vitest": "4.1.2"
|
|
91
94
|
},
|
|
92
95
|
"engines": {
|
|
93
96
|
"node": ">=22"
|