create-icebreaker 0.0.0 → 0.1.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/README.md +21 -11
- package/bin/create-icebreaker.js +1 -221
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +186 -0
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
# create-icebreaker
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Interactive bootstrapper for the icebreaker monorepo template. It scaffolds from the npm package and trims templates based on your selections.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
7
|
-
- `pnpm create icebreaker
|
|
8
|
-
- `npm create icebreaker@latest
|
|
7
|
+
- `pnpm create icebreaker`
|
|
8
|
+
- `npm create icebreaker@latest`
|
|
9
9
|
|
|
10
10
|
By default this:
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
12
|
+
- uses npm templates by default (no GitHub needed)
|
|
13
|
+
- asks for the project directory (defaults to `icebreaker-monorepo`)
|
|
14
|
+
- asks which templates to keep (default keeps none)
|
|
15
|
+
- updates the root `package.json` name
|
|
16
|
+
|
|
17
|
+
## Templates
|
|
18
|
+
|
|
19
|
+
Available template keys:
|
|
20
|
+
|
|
21
|
+
- `unbuild`
|
|
22
|
+
- `tsup`
|
|
23
|
+
- `tsdown`
|
|
24
|
+
- `vue-lib`
|
|
25
|
+
- `vue-hono`
|
|
26
|
+
- `hono-server`
|
|
27
|
+
- `vitepress`
|
|
28
|
+
- `cli`
|
|
15
29
|
|
|
16
30
|
## Flags
|
|
17
31
|
|
|
18
|
-
- `--
|
|
19
|
-
- `--branch <branch-or-tag>`: choose a branch or tag
|
|
20
|
-
- `--no-clean`: skip running `monorepo clean`
|
|
21
|
-
- `--include-private`: include private packages when cleaning
|
|
32
|
+
- `--templates <list>`: comma-separated template keys or indexes to keep (e.g. `tsup,vue-hono` or `1,5`)
|
|
22
33
|
- `--force`: overwrite a non-empty target directory
|
|
23
|
-
- `--agent <pnpm|npm>`: force which tool to run the cleanup with
|
package/bin/create-icebreaker.js
CHANGED
|
@@ -1,222 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import fs from 'node:fs/promises'
|
|
4
|
-
import path from 'node:path'
|
|
5
|
-
import process from 'node:process'
|
|
6
|
-
|
|
7
|
-
const DEFAULT_REPO = 'sonofmagic/monorepo-template'
|
|
8
|
-
const DEFAULT_BRANCH = 'main'
|
|
9
|
-
|
|
10
|
-
function printHelp() {
|
|
11
|
-
console.log([
|
|
12
|
-
'Usage: create-icebreaker [dir] [--repo <repo>] [--branch <branch>]',
|
|
13
|
-
'Options:',
|
|
14
|
-
' --repo <repo> GitHub repo or git url to clone (default sonofmagic/monorepo-template)',
|
|
15
|
-
' --branch <branch> Branch or tag to checkout (default main)',
|
|
16
|
-
' --no-clean Skip running monorepo clean after download',
|
|
17
|
-
' --include-private Run clean with private packages included',
|
|
18
|
-
' --force Remove existing target directory before cloning',
|
|
19
|
-
' --agent <pnpm|npm> Force package manager used for cleanup (default auto-detect)',
|
|
20
|
-
' -h, --help Show this help message',
|
|
21
|
-
].join('\n'))
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function parseArgs(argv) {
|
|
25
|
-
const options = {
|
|
26
|
-
targetDir: 'icebreaker-monorepo',
|
|
27
|
-
repo: DEFAULT_REPO,
|
|
28
|
-
branch: DEFAULT_BRANCH,
|
|
29
|
-
clean: true,
|
|
30
|
-
force: false,
|
|
31
|
-
includePrivate: false,
|
|
32
|
-
agent: undefined,
|
|
33
|
-
}
|
|
34
|
-
const positionals = []
|
|
35
|
-
for (let i = 0; i < argv.length; i++) {
|
|
36
|
-
const arg = argv[i]
|
|
37
|
-
if (arg === '--repo' && argv[i + 1]) {
|
|
38
|
-
options.repo = argv[++i]
|
|
39
|
-
continue
|
|
40
|
-
}
|
|
41
|
-
if (arg.startsWith('--repo=')) {
|
|
42
|
-
options.repo = arg.split('=')[1] || options.repo
|
|
43
|
-
continue
|
|
44
|
-
}
|
|
45
|
-
if (arg === '--branch' && argv[i + 1]) {
|
|
46
|
-
options.branch = argv[++i]
|
|
47
|
-
continue
|
|
48
|
-
}
|
|
49
|
-
if (arg.startsWith('--branch=')) {
|
|
50
|
-
options.branch = arg.split('=')[1] || options.branch
|
|
51
|
-
continue
|
|
52
|
-
}
|
|
53
|
-
if (arg === '--no-clean') {
|
|
54
|
-
options.clean = false
|
|
55
|
-
continue
|
|
56
|
-
}
|
|
57
|
-
if (arg === '--clean') {
|
|
58
|
-
options.clean = true
|
|
59
|
-
continue
|
|
60
|
-
}
|
|
61
|
-
if (arg === '--include-private') {
|
|
62
|
-
options.includePrivate = true
|
|
63
|
-
continue
|
|
64
|
-
}
|
|
65
|
-
if (arg === '--force') {
|
|
66
|
-
options.force = true
|
|
67
|
-
continue
|
|
68
|
-
}
|
|
69
|
-
if (arg === '--agent' && argv[i + 1]) {
|
|
70
|
-
options.agent = argv[++i]
|
|
71
|
-
continue
|
|
72
|
-
}
|
|
73
|
-
if (arg.startsWith('--agent=')) {
|
|
74
|
-
options.agent = arg.split('=')[1] || options.agent
|
|
75
|
-
continue
|
|
76
|
-
}
|
|
77
|
-
if (arg === '-h' || arg === '--help') {
|
|
78
|
-
options.help = true
|
|
79
|
-
continue
|
|
80
|
-
}
|
|
81
|
-
if (!arg.startsWith('-')) {
|
|
82
|
-
positionals.push(arg)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
if (positionals.length) {
|
|
86
|
-
options.targetDir = positionals[0]
|
|
87
|
-
}
|
|
88
|
-
return options
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function normalizeRepo(repo) {
|
|
92
|
-
if (repo.startsWith('http')) {
|
|
93
|
-
return repo
|
|
94
|
-
}
|
|
95
|
-
if (repo.startsWith('gh:')) {
|
|
96
|
-
return `https://github.com/${repo.slice(3)}.git`
|
|
97
|
-
}
|
|
98
|
-
if (/^[\w.-]+\/[\w.-]+$/.test(repo)) {
|
|
99
|
-
return `https://github.com/${repo}.git`
|
|
100
|
-
}
|
|
101
|
-
return repo
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async function isEmptyDir(dir) {
|
|
105
|
-
try {
|
|
106
|
-
const entries = await fs.readdir(dir)
|
|
107
|
-
return entries.length === 0
|
|
108
|
-
}
|
|
109
|
-
catch (error) {
|
|
110
|
-
if (error && error.code === 'ENOENT') {
|
|
111
|
-
return true
|
|
112
|
-
}
|
|
113
|
-
throw error
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async function prepareTarget(dir, force) {
|
|
118
|
-
const empty = await isEmptyDir(dir)
|
|
119
|
-
if (empty) {
|
|
120
|
-
await fs.mkdir(dir, { recursive: true })
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
if (!force) {
|
|
124
|
-
throw new Error(`Target directory ${dir} is not empty. Pass --force to overwrite.`)
|
|
125
|
-
}
|
|
126
|
-
await fs.rm(dir, { recursive: true, force: true })
|
|
127
|
-
await fs.mkdir(dir, { recursive: true })
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function runCommand(command, args, options) {
|
|
131
|
-
return new Promise((resolve, reject) => {
|
|
132
|
-
const child = spawn(command, args, {
|
|
133
|
-
stdio: 'inherit',
|
|
134
|
-
...options,
|
|
135
|
-
})
|
|
136
|
-
child.on('error', reject)
|
|
137
|
-
child.on('close', (code) => {
|
|
138
|
-
if (code && code !== 0) {
|
|
139
|
-
reject(new Error(`${command} ${args.join(' ')} exited with code ${code}`))
|
|
140
|
-
return
|
|
141
|
-
}
|
|
142
|
-
resolve()
|
|
143
|
-
})
|
|
144
|
-
})
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async function cloneRepo(repo, branch, targetDir) {
|
|
148
|
-
const normalized = normalizeRepo(repo)
|
|
149
|
-
console.log(`Cloning ${normalized} (branch ${branch})...`)
|
|
150
|
-
await runCommand('git', ['clone', '--depth', '1', '--branch', branch, normalized, targetDir])
|
|
151
|
-
await fs.rm(path.join(targetDir, '.git'), { recursive: true, force: true })
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function detectAgent(userAgent) {
|
|
155
|
-
if (!userAgent) {
|
|
156
|
-
return 'pnpm'
|
|
157
|
-
}
|
|
158
|
-
const first = userAgent.split(' ')[0] || ''
|
|
159
|
-
if (first.startsWith('pnpm/')) {
|
|
160
|
-
return 'pnpm'
|
|
161
|
-
}
|
|
162
|
-
if (first.startsWith('npm/')) {
|
|
163
|
-
return 'npm'
|
|
164
|
-
}
|
|
165
|
-
return 'pnpm'
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function getCleanCommand(agent, includePrivate) {
|
|
169
|
-
const usePnpm = agent === 'pnpm'
|
|
170
|
-
const runner = usePnpm ? 'pnpm' : 'npx'
|
|
171
|
-
const args = usePnpm
|
|
172
|
-
? ['dlx', '@icebreakers/monorepo@latest', 'clean', '--yes']
|
|
173
|
-
: ['--yes', '@icebreakers/monorepo@latest', 'clean', '--yes']
|
|
174
|
-
if (includePrivate) {
|
|
175
|
-
args.push('--include-private')
|
|
176
|
-
}
|
|
177
|
-
return { runner, args }
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async function runClean(targetDir, agent, includePrivate) {
|
|
181
|
-
const { runner, args } = getCleanCommand(agent, includePrivate)
|
|
182
|
-
console.log(`Running ${runner} ${args.join(' ')} in ${targetDir}`)
|
|
183
|
-
await runCommand(runner, args, { cwd: targetDir })
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function printNextSteps(targetDir, cleanRan) {
|
|
187
|
-
const relative = path.relative(process.cwd(), targetDir) || '.'
|
|
188
|
-
console.log('\nAll set! Next steps:')
|
|
189
|
-
console.log(` cd ${relative}`)
|
|
190
|
-
if (!cleanRan) {
|
|
191
|
-
console.log(' pnpm dlx @icebreakers/monorepo@latest clean --yes')
|
|
192
|
-
}
|
|
193
|
-
console.log(' pnpm install')
|
|
194
|
-
console.log(' pnpm dev')
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async function main() {
|
|
198
|
-
const parsed = parseArgs(process.argv.slice(2))
|
|
199
|
-
if (parsed.help) {
|
|
200
|
-
printHelp()
|
|
201
|
-
return
|
|
202
|
-
}
|
|
203
|
-
const targetDir = path.resolve(process.cwd(), parsed.targetDir)
|
|
204
|
-
try {
|
|
205
|
-
await prepareTarget(targetDir, parsed.force)
|
|
206
|
-
await cloneRepo(parsed.repo, parsed.branch, targetDir)
|
|
207
|
-
if (parsed.clean) {
|
|
208
|
-
const agent = parsed.agent || detectAgent(process.env.npm_config_user_agent)
|
|
209
|
-
await runClean(targetDir, agent, parsed.includePrivate)
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
console.log('Skip clean step per --no-clean')
|
|
213
|
-
}
|
|
214
|
-
printNextSteps(targetDir, parsed.clean)
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
console.error('[create-icebreaker]', error?.message || error)
|
|
218
|
-
process.exitCode = 1
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
main()
|
|
2
|
+
import '../dist/index.mjs'
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { Command, checkbox, input, shouldSkipTemplatePath, skeletonDir, templateChoices, templatesDir, toWorkspaceGitignorePath } from "@icebreakers/monorepo-templates";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
|
|
6
|
+
//#region src/constants.ts
|
|
7
|
+
const DEFAULT_TARGET = "icebreaker-monorepo";
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/fs-utils.ts
|
|
11
|
+
async function isEmptyDir(dir) {
|
|
12
|
+
try {
|
|
13
|
+
return (await fs.readdir(dir)).length === 0;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (error && error.code === "ENOENT") return true;
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function prepareTarget(dir, force) {
|
|
20
|
+
if (await isEmptyDir(dir)) {
|
|
21
|
+
await fs.mkdir(dir, { recursive: true });
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!force) throw new Error(`Target directory ${dir} is not empty. Pass --force to overwrite.`);
|
|
25
|
+
await fs.rm(dir, {
|
|
26
|
+
recursive: true,
|
|
27
|
+
force: true
|
|
28
|
+
});
|
|
29
|
+
await fs.mkdir(dir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
async function copyDirContents(sourceDir, targetDir, rootDir = sourceDir) {
|
|
32
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
33
|
+
const entries = await fs.readdir(sourceDir, { withFileTypes: true });
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
const from = path.join(sourceDir, entry.name);
|
|
36
|
+
if (shouldSkipTemplatePath(rootDir, from)) continue;
|
|
37
|
+
const targetName = toWorkspaceGitignorePath(entry.name);
|
|
38
|
+
const to = path.join(targetDir, targetName);
|
|
39
|
+
if (entry.isDirectory()) {
|
|
40
|
+
await copyDirContents(from, to, rootDir);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (entry.isSymbolicLink()) {
|
|
44
|
+
const link = await fs.readlink(from);
|
|
45
|
+
await fs.symlink(link, to);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
await fs.cp(from, to);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/package-json.ts
|
|
54
|
+
async function updateRootPackageJson(targetDir, projectName) {
|
|
55
|
+
const pkgPath = path.join(targetDir, "package.json");
|
|
56
|
+
const raw = await fs.readFile(pkgPath, "utf8");
|
|
57
|
+
const pkg = JSON.parse(raw);
|
|
58
|
+
pkg.name = projectName;
|
|
59
|
+
const devDependencies = pkg.devDependencies;
|
|
60
|
+
if (devDependencies && devDependencies["@icebreakers/monorepo"]) {
|
|
61
|
+
delete devDependencies["@icebreakers/monorepo"];
|
|
62
|
+
if (Object.keys(devDependencies).length === 0) delete pkg.devDependencies;
|
|
63
|
+
}
|
|
64
|
+
const scripts = pkg.scripts;
|
|
65
|
+
if (scripts) {
|
|
66
|
+
const nextScripts = {};
|
|
67
|
+
for (const [key, value] of Object.entries(scripts)) {
|
|
68
|
+
if (typeof value === "string" && value.includes("monorepo")) continue;
|
|
69
|
+
nextScripts[key] = value;
|
|
70
|
+
}
|
|
71
|
+
if (Object.keys(nextScripts).length) pkg.scripts = nextScripts;
|
|
72
|
+
else delete pkg.scripts;
|
|
73
|
+
}
|
|
74
|
+
await fs.writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf8");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/templates.ts
|
|
79
|
+
function parseTemplateInput(input$1) {
|
|
80
|
+
const selections = /* @__PURE__ */ new Set();
|
|
81
|
+
const unknown = [];
|
|
82
|
+
const tokens = input$1.split(/[,\\s]+/).map((token) => token.trim()).filter(Boolean);
|
|
83
|
+
for (const token of tokens) {
|
|
84
|
+
const normalized = token.toLowerCase();
|
|
85
|
+
if (/^\\d+$/.test(normalized)) {
|
|
86
|
+
const choice = templateChoices[Number(normalized) - 1];
|
|
87
|
+
if (choice) selections.add(choice.key);
|
|
88
|
+
else unknown.push(token);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const match = templateChoices.find((item) => item.key === normalized);
|
|
92
|
+
if (match) selections.add(match.key);
|
|
93
|
+
else unknown.push(token);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
selections: Array.from(selections),
|
|
97
|
+
unknown
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function resolveTemplateSelections(input$1) {
|
|
101
|
+
if (!input$1) return {
|
|
102
|
+
selections: [],
|
|
103
|
+
unknown: []
|
|
104
|
+
};
|
|
105
|
+
return parseTemplateInput(input$1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/prompts.ts
|
|
110
|
+
async function promptTargetDir(defaultDir) {
|
|
111
|
+
return ((await input({
|
|
112
|
+
message: `项目创建目录(默认 ${defaultDir}):`,
|
|
113
|
+
default: defaultDir
|
|
114
|
+
}))?.trim?.() ?? defaultDir) || defaultDir;
|
|
115
|
+
}
|
|
116
|
+
async function promptTemplates() {
|
|
117
|
+
return await checkbox({
|
|
118
|
+
message: "请选择要保留的模板(默认不选择):",
|
|
119
|
+
choices: templateChoices.map((item) => ({
|
|
120
|
+
name: `${item.key} - ${item.label}`,
|
|
121
|
+
value: item.key
|
|
122
|
+
}))
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/source-npm.ts
|
|
128
|
+
async function copySelectedTemplates(targetDir, selectedTemplates) {
|
|
129
|
+
if (!selectedTemplates.length) return;
|
|
130
|
+
const selected = new Set(selectedTemplates);
|
|
131
|
+
for (const template of templateChoices) {
|
|
132
|
+
if (!selected.has(template.key)) continue;
|
|
133
|
+
await copyDirContents(path.join(templatesDir, template.source), path.join(targetDir, template.target));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async function scaffoldFromNpm(targetDir, selectedTemplates) {
|
|
137
|
+
await copyDirContents(skeletonDir, targetDir);
|
|
138
|
+
await copySelectedTemplates(targetDir, selectedTemplates);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/index.ts
|
|
143
|
+
function printNextSteps(targetDir) {
|
|
144
|
+
const relative = path.relative(process.cwd(), targetDir) || ".";
|
|
145
|
+
process.stdout.write([
|
|
146
|
+
"",
|
|
147
|
+
"All set! Next steps:",
|
|
148
|
+
` cd ${relative}`,
|
|
149
|
+
" pnpm install",
|
|
150
|
+
" pnpm dev",
|
|
151
|
+
""
|
|
152
|
+
].join("\n"));
|
|
153
|
+
}
|
|
154
|
+
async function runCreate(targetDirInput, options) {
|
|
155
|
+
const isInteractive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
156
|
+
let targetInput = targetDirInput || DEFAULT_TARGET;
|
|
157
|
+
if (isInteractive) targetInput = await promptTargetDir(targetInput);
|
|
158
|
+
let selectedTemplates = [];
|
|
159
|
+
if (options.templates) {
|
|
160
|
+
const { selections, unknown } = resolveTemplateSelections(options.templates);
|
|
161
|
+
if (unknown.length) process.stderr.write(`忽略未知模板:${unknown.join(", ")}\n`);
|
|
162
|
+
selectedTemplates = selections;
|
|
163
|
+
} else if (isInteractive) selectedTemplates = await promptTemplates();
|
|
164
|
+
const targetDir = path.resolve(process.cwd(), targetInput);
|
|
165
|
+
const projectName = path.basename(targetDir) || targetInput;
|
|
166
|
+
await prepareTarget(targetDir, Boolean(options.force));
|
|
167
|
+
await scaffoldFromNpm(targetDir, selectedTemplates);
|
|
168
|
+
await updateRootPackageJson(targetDir, projectName);
|
|
169
|
+
printNextSteps(targetDir);
|
|
170
|
+
}
|
|
171
|
+
const program = new Command();
|
|
172
|
+
program.name("create-icebreaker").description("Bootstrap the icebreaker monorepo template").argument("[dir]", "Target directory", DEFAULT_TARGET).option("-t, --templates <list>", "Comma-separated template keys or indexes to keep").option("-f, --force", "Remove existing target directory before scaffolding", false).action(async (dir, options) => {
|
|
173
|
+
try {
|
|
174
|
+
await runCreate(dir, options);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
process.stderr.write(`[create-icebreaker] ${error instanceof Error ? error.message : error}\n`);
|
|
177
|
+
process.exitCode = 1;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
program.parseAsync(process.argv).catch((error) => {
|
|
181
|
+
process.stderr.write(`[create-icebreaker] ${error instanceof Error ? error.message : error}\n`);
|
|
182
|
+
process.exitCode = 1;
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
export { };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-icebreaker",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.1.0",
|
|
5
5
|
"description": "Bootstrap the icebreaker monorepo template via npm create/pnpm create with optional cleanup",
|
|
6
6
|
"author": "ice breaker <1324318532@qq.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -24,15 +24,22 @@
|
|
|
24
24
|
"create-icebreaker": "bin/create-icebreaker.js"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
|
-
"bin"
|
|
27
|
+
"bin",
|
|
28
|
+
"dist"
|
|
28
29
|
],
|
|
29
30
|
"engines": {
|
|
30
31
|
"node": ">=18.0.0"
|
|
31
32
|
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@icebreakers/monorepo-templates": "0.1.0"
|
|
35
|
+
},
|
|
32
36
|
"publishConfig": {
|
|
33
37
|
"access": "public"
|
|
34
38
|
},
|
|
35
39
|
"scripts": {
|
|
40
|
+
"dev": "tsdown --watch --sourcemap",
|
|
41
|
+
"build": "tsdown",
|
|
42
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
36
43
|
"lint": "eslint .",
|
|
37
44
|
"test": "vitest run --passWithNoTests"
|
|
38
45
|
}
|