+134
-132
cli.ts
+134
-132
cli.ts
···
9
9
import { join } from "node:path";
10
10
import * as p from "@clack/prompts";
11
11
import { setTimeout } from "node:timers/promises";
12
+
import { version } from "./package.json";
12
13
13
14
async function main() {
14
-
console.clear();
15
-
16
-
p.intro("🥞 Tacy Stack Generator");
17
-
18
-
// Get project name
19
-
const projectName = await p.text({
20
-
message: "What is your project name?",
21
-
placeholder: "my-app",
22
-
validate(value) {
23
-
if (!value) return "Project name is required";
24
-
if (!/^[a-z0-9-_]+$/i.test(value)) {
25
-
return "Project name can only contain letters, numbers, hyphens, and underscores";
26
-
}
27
-
const targetDir = join(process.cwd(), value);
28
-
if (existsSync(targetDir)) {
29
-
return `Directory "${value}" already exists!`;
30
-
}
31
-
},
32
-
});
33
-
34
-
if (p.isCancel(projectName)) {
35
-
p.cancel("Operation cancelled");
36
-
process.exit(0);
37
-
}
38
-
39
-
const targetDir = join(process.cwd(), projectName as string);
40
-
const templateDir = import.meta.dir;
41
-
42
-
const s = p.spinner();
43
-
44
-
try {
45
-
// Create directory
46
-
s.start("Creating project directory");
47
-
mkdirSync(targetDir, { recursive: true });
48
-
await setTimeout(200);
49
-
s.stop("Created project directory");
50
-
51
-
// Copy template files
52
-
s.start("Copying template files");
53
-
await $`cp -r ${templateDir}/* ${targetDir}/`.quiet();
54
-
55
-
// Copy dotfiles explicitly
56
-
const dotfiles = [".env.example", ".gitignore", ".gitattributes"];
57
-
for (const dotfile of dotfiles) {
58
-
const source = join(templateDir, dotfile);
59
-
const dest = join(targetDir, dotfile);
60
-
if (existsSync(source)) {
61
-
await $`cp ${source} ${dest}`.quiet();
62
-
}
63
-
}
64
-
65
-
// Copy .github directory if it exists
66
-
const githubDir = join(templateDir, ".github");
67
-
if (existsSync(githubDir)) {
68
-
await $`cp -r ${githubDir} ${targetDir}/.github`.quiet();
69
-
}
70
-
71
-
await setTimeout(200);
72
-
s.stop("Copied template files");
73
-
74
-
// Remove CLI and template files
75
-
s.start("Cleaning up template files");
76
-
const filesToRemove = [
77
-
"cli.ts",
78
-
"TEMPLATE.md",
79
-
"TEMPLATE_SETUP_SUMMARY.md",
80
-
"CLI_SUMMARY.md",
81
-
"PUBLISHING.md",
82
-
"template.toml",
83
-
".github/TEMPLATE_SETUP.md",
84
-
];
85
-
86
-
for (const file of filesToRemove) {
87
-
const filePath = join(targetDir, file);
88
-
if (existsSync(filePath)) {
89
-
await $`rm -rf ${filePath}`.quiet();
90
-
}
91
-
}
92
-
await setTimeout(200);
93
-
s.stop("Cleaned up template files");
94
-
95
-
// Update package.json
96
-
s.start("Configuring package.json");
97
-
const packageJsonPath = join(targetDir, "package.json");
98
-
const packageJson = await Bun.file(packageJsonPath).json();
99
-
packageJson.name = projectName;
100
-
packageJson.version = "0.1.0";
101
-
delete packageJson.bin;
102
-
// Remove @clack/prompts from dependencies since it's only for the CLI
103
-
if (packageJson.dependencies?.["@clack/prompts"]) {
104
-
delete packageJson.dependencies["@clack/prompts"];
105
-
}
106
-
await Bun.write(packageJsonPath, JSON.stringify(packageJson, null, "\t") + "\n");
107
-
await setTimeout(200);
108
-
s.stop("Configured package.json");
109
-
110
-
// Initialize git
111
-
s.start("Initializing git repository");
112
-
await $`cd ${targetDir} && git init`.quiet();
113
-
await setTimeout(200);
114
-
s.stop("Initialized git repository");
115
-
116
-
// Create .env
117
-
s.start("Creating .env file");
118
-
await $`cd ${targetDir} && cp .env.example .env`.quiet();
119
-
await setTimeout(200);
120
-
s.stop("Created .env file");
121
-
122
-
// Install dependencies
123
-
s.start("Installing dependencies");
124
-
await $`cd ${targetDir} && bun install`.quiet();
125
-
s.stop("Installed dependencies");
126
-
127
-
// Setup database
128
-
s.start("Setting up database");
129
-
await $`cd ${targetDir} && bun run db:push`.quiet();
130
-
s.stop("Set up database");
131
-
132
-
} catch (error) {
133
-
s.stop("Failed");
134
-
p.cancel(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
135
-
process.exit(1);
136
-
}
137
-
138
-
p.outro("🎉 Project created successfully!");
139
-
140
-
p.note(
141
-
`cd ${projectName}\nbun dev`,
142
-
"Next steps"
143
-
);
15
+
console.clear();
16
+
17
+
p.intro(`🥞 Tacy Stack Generator @ ${version}`);
18
+
19
+
// Get project name
20
+
const projectName = await p.text({
21
+
message: "What is your project name?",
22
+
placeholder: "my-app",
23
+
validate(value) {
24
+
if (!value) return "Project name is required";
25
+
if (!/^[a-z0-9-_]+$/i.test(value)) {
26
+
return "Project name can only contain letters, numbers, hyphens, and underscores";
27
+
}
28
+
const targetDir = join(process.cwd(), value);
29
+
if (existsSync(targetDir)) {
30
+
return `Directory "${value}" already exists!`;
31
+
}
32
+
},
33
+
});
34
+
35
+
if (p.isCancel(projectName)) {
36
+
p.cancel("Operation cancelled");
37
+
process.exit(0);
38
+
}
39
+
40
+
const targetDir = join(process.cwd(), projectName as string);
41
+
const templateDir = import.meta.dir;
42
+
43
+
const s = p.spinner();
44
+
45
+
try {
46
+
// Create directory
47
+
s.start("Creating project directory");
48
+
mkdirSync(targetDir, { recursive: true });
49
+
await setTimeout(200);
50
+
s.stop("Created project directory");
51
+
52
+
// Copy template files
53
+
s.start("Copying template files");
54
+
await $`cp -r ${templateDir}/* ${targetDir}/`.quiet();
55
+
56
+
// Copy dotfiles explicitly
57
+
const dotfiles = [".env.example", ".gitignore", ".gitattributes"];
58
+
for (const dotfile of dotfiles) {
59
+
const source = join(templateDir, dotfile);
60
+
const dest = join(targetDir, dotfile);
61
+
if (existsSync(source)) {
62
+
await $`cp ${source} ${dest}`.quiet();
63
+
}
64
+
}
65
+
66
+
// Copy .github directory if it exists
67
+
const githubDir = join(templateDir, ".github");
68
+
if (existsSync(githubDir)) {
69
+
await $`cp -r ${githubDir} ${targetDir}/.github`.quiet();
70
+
}
71
+
72
+
await setTimeout(200);
73
+
s.stop("Copied template files");
74
+
75
+
// Remove CLI and template files
76
+
s.start("Cleaning up template files");
77
+
const filesToRemove = [
78
+
"cli.ts",
79
+
"TEMPLATE.md",
80
+
"TEMPLATE_SETUP_SUMMARY.md",
81
+
"CLI_SUMMARY.md",
82
+
"PUBLISHING.md",
83
+
"template.toml",
84
+
".github/TEMPLATE_SETUP.md",
85
+
];
86
+
87
+
for (const file of filesToRemove) {
88
+
const filePath = join(targetDir, file);
89
+
if (existsSync(filePath)) {
90
+
await $`rm -rf ${filePath}`.quiet();
91
+
}
92
+
}
93
+
await setTimeout(200);
94
+
s.stop("Cleaned up template files");
95
+
96
+
// Update package.json
97
+
s.start("Configuring package.json");
98
+
const packageJsonPath = join(targetDir, "package.json");
99
+
const packageJson = await Bun.file(packageJsonPath).json();
100
+
packageJson.name = projectName;
101
+
packageJson.version = "0.1.0";
102
+
delete packageJson.bin;
103
+
// Remove @clack/prompts from dependencies since it's only for the CLI
104
+
if (packageJson.dependencies?.["@clack/prompts"]) {
105
+
delete packageJson.dependencies["@clack/prompts"];
106
+
}
107
+
await Bun.write(
108
+
packageJsonPath,
109
+
JSON.stringify(packageJson, null, "\t") + "\n",
110
+
);
111
+
await setTimeout(200);
112
+
s.stop("Configured package.json");
113
+
114
+
// Initialize git
115
+
s.start("Initializing git repository");
116
+
await $`cd ${targetDir} && git init`.quiet();
117
+
await setTimeout(200);
118
+
s.stop("Initialized git repository");
119
+
120
+
// Create .env
121
+
s.start("Creating .env file");
122
+
await $`cd ${targetDir} && cp .env.example .env`.quiet();
123
+
await setTimeout(200);
124
+
s.stop("Created .env file");
125
+
126
+
// Install dependencies
127
+
s.start("Installing dependencies");
128
+
await $`cd ${targetDir} && bun install`.quiet();
129
+
s.stop("Installed dependencies");
130
+
131
+
// Setup database
132
+
s.start("Setting up database");
133
+
await $`cd ${targetDir} && bun run db:push`.quiet();
134
+
s.stop("Set up database");
135
+
} catch (error) {
136
+
s.stop("Failed");
137
+
p.cancel(
138
+
`Error: ${error instanceof Error ? error.message : "Unknown error"}`,
139
+
);
140
+
process.exit(1);
141
+
}
142
+
143
+
p.outro("🎉 Project created successfully!");
144
+
145
+
p.note(`cd ${projectName}\nbun dev`, "Next steps");
144
146
}
145
147
146
148
main().catch((error) => {
147
-
console.error(error);
148
-
process.exit(1);
149
+
console.error(error);
150
+
process.exit(1);
149
151
});