create-morax 1.0.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 +139 -0
- package/dist/index.js +457 -0
- package/dist/index.js.map +1 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<div style="display: flex; align-items: center; justify-content: center; gap: 18px; margin-bottom: 12px;">
|
|
4
|
+
<img src="https://res.cloudinary.com/dnvl8mqba/image/upload/v1779642846/Morax/morax_yhqyn8.webp" alt="Morax Logo" width="70" style="border-radius: 12px;" />
|
|
5
|
+
<h1 style="border-bottom: none; margin: 0; font-size: 2.8rem; font-weight: 900; letter-spacing: 3px; line-height: 1;">MORAX</h1>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
### _The Next-Generation `pnpm` Monorepo & Workspace Orchestrator_
|
|
9
|
+
|
|
10
|
+
[](https://www.npmjs.com/package/@elitedv/morax)
|
|
11
|
+
[](https://www.typescriptlang.org/)
|
|
12
|
+
[](https://pnpm.io/)
|
|
13
|
+
[](https://opensource.org/licenses/MIT)
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
A highly polished, interactive CLI that bootstraps custom, modern, high-performance <b>pnpm workspaces</b> in seconds.
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
[Quick Start](#-quick-start) • [Features](#-features-matrix) • [Workflow](#-dynamic-workspace-orchestration) • [Contributing](#-contributing)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
## 🚀 Quick Start
|
|
26
|
+
|
|
27
|
+
Initialize your new workspace instantly using:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm create morax@latest
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or using `pnpm`:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pnpm create morax
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Or using `bun`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bun create morax
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## ⚡ Dynamic Workspace Orchestration
|
|
48
|
+
|
|
49
|
+
Morax acts as a smart orchestrator. Instead of copy-pasting outdated boilerplate code, it executes official framework CLIs and programmatically connects them under the hood:
|
|
50
|
+
|
|
51
|
+
```mermaid
|
|
52
|
+
graph TD
|
|
53
|
+
A[npm create morax@latest] --> B[Interactive Configuration Prompt]
|
|
54
|
+
B -->|Setup Root| C[Create pnpm-workspace.yaml & turbo.json]
|
|
55
|
+
|
|
56
|
+
C --> D[Scaffold Applications]
|
|
57
|
+
D --> D1[Next.js App: npx create-next-app]
|
|
58
|
+
D --> D2[Express API: TypeScript Backend]
|
|
59
|
+
|
|
60
|
+
C --> E[Scaffold Shared Libraries]
|
|
61
|
+
E --> E1[packages/ui: shadcn init]
|
|
62
|
+
E --> E2[packages/db: prisma/drizzle init]
|
|
63
|
+
E --> E3[packages/configs: tsconfig & eslint]
|
|
64
|
+
|
|
65
|
+
D1 & D2 & E1 & E2 & E3 --> F[Link Workspace Packages]
|
|
66
|
+
F --> G[Inject workspace:* references into Package Manifests]
|
|
67
|
+
G --> H[Run pnpm install at Workspace Root]
|
|
68
|
+
H --> I[Ready to Code!]
|
|
69
|
+
|
|
70
|
+
style A fill:#8A2BE2,stroke:#fff,stroke-width:2px,color:#fff
|
|
71
|
+
style B fill:#1f1f1f,stroke:#8A2BE2,stroke-width:1px,color:#fff
|
|
72
|
+
style C fill:#1f1f1f,stroke:#8A2BE2,stroke-width:1px,color:#fff
|
|
73
|
+
style D fill:#007acc,stroke:#fff,stroke-width:1px,color:#fff
|
|
74
|
+
style E fill:#e25c00,stroke:#fff,stroke-width:1px,color:#fff
|
|
75
|
+
style F fill:#2ea44f,stroke:#fff,stroke-width:2px,color:#fff
|
|
76
|
+
style I fill:#2ea44f,stroke:#fff,stroke-width:2px,color:#fff
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### Interactive Prompts
|
|
82
|
+
|
|
83
|
+
Morax guides you step-by-step to customize your developer experience:
|
|
84
|
+
|
|
85
|
+
```ansi
|
|
86
|
+
? What is the name of your workspace? › my-morax-monorepo
|
|
87
|
+
? Which applications would you like to scaffold? ›
|
|
88
|
+
🎯 [x] Next.js Web App
|
|
89
|
+
🔌 [x] Express.js API
|
|
90
|
+
? Which packages would you like to configure? ›
|
|
91
|
+
🎨 [x] Shared UI Library (Tailwind + Shadcn)
|
|
92
|
+
🗃️ [x] Shared Database Client (Prisma + PostgreSQL)
|
|
93
|
+
⚙️ [x] Shared Linting & TypeScript Configurations
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Launch Development Server
|
|
97
|
+
|
|
98
|
+
Once setup is complete, navigate into your directory and launch the unified development server:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
cd my-morax-monorepo
|
|
102
|
+
pnpm dev
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## ✨ Features Matrix
|
|
108
|
+
|
|
109
|
+
### 🛠️ Workspace & Orchestration
|
|
110
|
+
|
|
111
|
+
- **create pnpm workspace monorepo with ease**
|
|
112
|
+
- **Zero-Config Workspaces:** Complete setup of `pnpm-workspace.yaml` and unified root lockfiles.
|
|
113
|
+
- **Turborepo Pipeline:** Lightning-fast, cached builds and concurrent tasks (`dev`, `build`, `lint`).
|
|
114
|
+
- **Automated Symlinking:** Direct injection of `"@workspace/ui": "workspace:*"` cross-package references.
|
|
115
|
+
- **Always Up-to-Date:** Pulls from the latest official framework generators dynamically.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 🤝 Contributing
|
|
120
|
+
|
|
121
|
+
We welcome contributions to make Morax even better!
|
|
122
|
+
|
|
123
|
+
1. **Fork** the repository
|
|
124
|
+
2. **Create** your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
125
|
+
3. **Commit** your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
126
|
+
4. **Push** to the branch (`git push origin feature/AmazingFeature`)
|
|
127
|
+
5. **Open** a Pull Request
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 📝 License
|
|
132
|
+
|
|
133
|
+
Distributed under the MIT License. See [LICENSE](file:///c:/Users/runak/Coding/Development/Morax/LICENSE) for details.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
<div align="center">
|
|
138
|
+
<sub>Made with 💜 by <a href="https://github.com/AshutoshDM1">AshutoshDM1</a> & <a href="https://github.com/elitedv">EliteDV Team</a></sub>
|
|
139
|
+
</div>
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import pc9 from "picocolors";
|
|
5
|
+
|
|
6
|
+
// src/core/runner.ts
|
|
7
|
+
import path6 from "path";
|
|
8
|
+
|
|
9
|
+
// src/core/startcli.ts
|
|
10
|
+
import gradient from "gradient-string";
|
|
11
|
+
import pc from "picocolors";
|
|
12
|
+
import { intro } from "@clack/prompts";
|
|
13
|
+
import boxen from "boxen";
|
|
14
|
+
var asciiArt = [
|
|
15
|
+
"\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557",
|
|
16
|
+
"\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D",
|
|
17
|
+
"\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2554\u255D ",
|
|
18
|
+
"\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557 ",
|
|
19
|
+
"\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u255D \u2588\u2588\u2557",
|
|
20
|
+
"\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D"
|
|
21
|
+
].join("\n");
|
|
22
|
+
function startCli() {
|
|
23
|
+
console.clear();
|
|
24
|
+
const moraxGradient = gradient(["#FF3E00", "#FF8C00", "#FFAE19"]);
|
|
25
|
+
console.log("\n");
|
|
26
|
+
console.log(moraxGradient(asciiArt));
|
|
27
|
+
console.log("\n");
|
|
28
|
+
intro(pc.yellow("\u{1F30C} Welcome to Morax \u2014 The Next-Gen Workspace Scaffolder"));
|
|
29
|
+
console.log(
|
|
30
|
+
boxen(
|
|
31
|
+
`\u26A1 ${pc.bold("Morax")} automates the setup of modern ${pc.cyan("pnpm workspaces")}, linking internal shared configurations, UI packages, and framework apps concurrently.`,
|
|
32
|
+
{
|
|
33
|
+
padding: 1,
|
|
34
|
+
margin: { top: 0, bottom: 1, left: 1, right: 1 },
|
|
35
|
+
borderStyle: "round",
|
|
36
|
+
borderColor: "yellow"
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/core/workspaceName.ts
|
|
43
|
+
import { text } from "@clack/prompts";
|
|
44
|
+
|
|
45
|
+
// src/utils/isCancel.ts
|
|
46
|
+
import { isCancel, cancel } from "@clack/prompts";
|
|
47
|
+
import pc2 from "picocolors";
|
|
48
|
+
function handleCancel(input) {
|
|
49
|
+
if (isCancel(input)) {
|
|
50
|
+
cancel(pc2.red("\u2716 Morax cancelled."));
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/core/workspaceName.ts
|
|
56
|
+
async function promptWorkspaceName() {
|
|
57
|
+
const nameInput = await text({
|
|
58
|
+
message: "What is the name of your new monorepo workspace?",
|
|
59
|
+
placeholder: "morax-workspace",
|
|
60
|
+
validate(value) {
|
|
61
|
+
if (value && value.includes(" ")) return "Workspace name cannot contain spaces!";
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
handleCancel(nameInput);
|
|
65
|
+
return String(nameInput).trim() || "morax-workspace";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/tasks/directories.ts
|
|
69
|
+
import { multiselect, spinner } from "@clack/prompts";
|
|
70
|
+
import fsPromises2 from "fs/promises";
|
|
71
|
+
import path2 from "path";
|
|
72
|
+
import pc4 from "picocolors";
|
|
73
|
+
|
|
74
|
+
// src/tasks/workspace.ts
|
|
75
|
+
import fsPromises from "fs/promises";
|
|
76
|
+
import path from "path";
|
|
77
|
+
|
|
78
|
+
// src/utils/exec.ts
|
|
79
|
+
import { exec } from "child_process";
|
|
80
|
+
import { promisify } from "util";
|
|
81
|
+
import pc3 from "picocolors";
|
|
82
|
+
var execAsync = promisify(exec);
|
|
83
|
+
async function runCommand(command, options = {}) {
|
|
84
|
+
if (!options.silent) {
|
|
85
|
+
console.log(pc3.cyan(`> ${command}`));
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
89
|
+
cwd: options.cwd,
|
|
90
|
+
env: { ...process.env, NODE_NO_WARNINGS: "1" }
|
|
91
|
+
});
|
|
92
|
+
if (!options.silent) {
|
|
93
|
+
if (stdout && stdout.trim()) {
|
|
94
|
+
console.log(stdout.trim());
|
|
95
|
+
}
|
|
96
|
+
if (stderr && stderr.trim()) {
|
|
97
|
+
console.log(pc3.yellow(stderr.trim()));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { stdout, stderr };
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (!options.silent) {
|
|
103
|
+
if (error.stdout && error.stdout.trim()) {
|
|
104
|
+
console.log(error.stdout.trim());
|
|
105
|
+
}
|
|
106
|
+
if (error.stderr && error.stderr.trim()) {
|
|
107
|
+
console.error(pc3.red(error.stderr.trim()));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/tasks/workspace.ts
|
|
115
|
+
async function generateWorkspaceConfig(name, directories, projectPath) {
|
|
116
|
+
await fsPromises.mkdir(projectPath, { recursive: true });
|
|
117
|
+
const workspaceYamlContent = [
|
|
118
|
+
"packages:",
|
|
119
|
+
...directories.map((dir) => ` - '${dir}/*'`),
|
|
120
|
+
""
|
|
121
|
+
].join("\n");
|
|
122
|
+
await fsPromises.writeFile(
|
|
123
|
+
path.join(projectPath, "pnpm-workspace.yaml"),
|
|
124
|
+
workspaceYamlContent,
|
|
125
|
+
"utf8"
|
|
126
|
+
);
|
|
127
|
+
await runCommand("pnpm init", { cwd: projectPath, silent: true });
|
|
128
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
129
|
+
const packageJsonRaw = await fsPromises.readFile(packageJsonPath, "utf8");
|
|
130
|
+
const pkg = JSON.parse(packageJsonRaw);
|
|
131
|
+
pkg.name = name;
|
|
132
|
+
pkg.description = "High-performance monorepo workspace generated by Morax";
|
|
133
|
+
pkg.private = true;
|
|
134
|
+
pkg.packageManager = "pnpm@9.15.4";
|
|
135
|
+
pkg.workspaces = directories.map((dir) => `${dir}/*`);
|
|
136
|
+
pkg.scripts = {
|
|
137
|
+
dev: "pnpm --filter morax-web dev"
|
|
138
|
+
};
|
|
139
|
+
delete pkg.main;
|
|
140
|
+
await fsPromises.writeFile(
|
|
141
|
+
packageJsonPath,
|
|
142
|
+
JSON.stringify(pkg, null, 2),
|
|
143
|
+
"utf8"
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/tasks/directories.ts
|
|
148
|
+
async function createDirectories(directories, projectPath) {
|
|
149
|
+
for (const dir of directories) {
|
|
150
|
+
const dirPath = path2.join(projectPath, dir);
|
|
151
|
+
await fsPromises2.mkdir(dirPath, { recursive: true });
|
|
152
|
+
await fsPromises2.writeFile(
|
|
153
|
+
path2.join(dirPath, ".gitkeep"),
|
|
154
|
+
`# Placeholder to ensure git tracks the empty ${dir}/ folder
|
|
155
|
+
`,
|
|
156
|
+
"utf8"
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function makeDirectories(name, projectPath) {
|
|
161
|
+
const directories = await multiselect({
|
|
162
|
+
message: "Which directories do you want to include in your workspace?",
|
|
163
|
+
options: [
|
|
164
|
+
{
|
|
165
|
+
value: "apps",
|
|
166
|
+
label: "apps/*",
|
|
167
|
+
hint: "For frontend apps and backend services"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
value: "packages",
|
|
171
|
+
label: "packages/*",
|
|
172
|
+
hint: "For shared components, configs, and utilities"
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
required: true
|
|
176
|
+
});
|
|
177
|
+
handleCancel(directories);
|
|
178
|
+
const s = spinner();
|
|
179
|
+
console.log("\n");
|
|
180
|
+
s.start("Generating workspace configs...");
|
|
181
|
+
try {
|
|
182
|
+
await generateWorkspaceConfig(
|
|
183
|
+
name,
|
|
184
|
+
directories,
|
|
185
|
+
projectPath
|
|
186
|
+
);
|
|
187
|
+
await createDirectories(
|
|
188
|
+
directories,
|
|
189
|
+
projectPath
|
|
190
|
+
);
|
|
191
|
+
s.stop(pc4.green("\u2714 Success: Generated Workspace Root & Folder Structures"));
|
|
192
|
+
} catch (error) {
|
|
193
|
+
s.stop(pc4.red("\u2716 Failed: Workspace generation failed"));
|
|
194
|
+
console.error(pc4.red(`
|
|
195
|
+
Error details: ${error.message || error}`));
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
console.log("\n");
|
|
199
|
+
return directories;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/tasks/prettier.ts
|
|
203
|
+
import { confirm, spinner as spinner2 } from "@clack/prompts";
|
|
204
|
+
import pc5 from "picocolors";
|
|
205
|
+
import fsPromises3 from "fs/promises";
|
|
206
|
+
import path3 from "path";
|
|
207
|
+
async function promptPrettier() {
|
|
208
|
+
return await confirm({
|
|
209
|
+
message: "Do you want to setup Prettier code formatting?",
|
|
210
|
+
initialValue: true
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async function setupPrettier(projectPath) {
|
|
214
|
+
await runCommand("pnpm add -D -E prettier -w", { cwd: projectPath });
|
|
215
|
+
const prettierrc = {
|
|
216
|
+
semi: true,
|
|
217
|
+
singleQuote: true,
|
|
218
|
+
tabWidth: 2,
|
|
219
|
+
trailingComma: "all",
|
|
220
|
+
printWidth: 100
|
|
221
|
+
};
|
|
222
|
+
await fsPromises3.writeFile(
|
|
223
|
+
path3.join(projectPath, ".prettierrc"),
|
|
224
|
+
JSON.stringify(prettierrc, null, 2),
|
|
225
|
+
"utf8"
|
|
226
|
+
);
|
|
227
|
+
const prettierignore = [
|
|
228
|
+
"# Dependencies",
|
|
229
|
+
"node_modules/",
|
|
230
|
+
"jspm_packages/",
|
|
231
|
+
"web_modules/",
|
|
232
|
+
"",
|
|
233
|
+
"# Build and outputs",
|
|
234
|
+
"dist/",
|
|
235
|
+
"build/",
|
|
236
|
+
".next/",
|
|
237
|
+
"out/",
|
|
238
|
+
".turbo/",
|
|
239
|
+
"",
|
|
240
|
+
"# Configuration locks",
|
|
241
|
+
"pnpm-lock.yaml",
|
|
242
|
+
"",
|
|
243
|
+
"# Environment files",
|
|
244
|
+
".env",
|
|
245
|
+
".env.*",
|
|
246
|
+
""
|
|
247
|
+
].join("\n");
|
|
248
|
+
await fsPromises3.writeFile(
|
|
249
|
+
path3.join(projectPath, ".prettierignore"),
|
|
250
|
+
prettierignore,
|
|
251
|
+
"utf8"
|
|
252
|
+
);
|
|
253
|
+
const rootPackagePath = path3.join(projectPath, "package.json");
|
|
254
|
+
const rootPackageContent = await fsPromises3.readFile(rootPackagePath, "utf8");
|
|
255
|
+
const pkg = JSON.parse(rootPackageContent);
|
|
256
|
+
pkg.scripts = {
|
|
257
|
+
...pkg.scripts || {},
|
|
258
|
+
format: "prettier --write ."
|
|
259
|
+
};
|
|
260
|
+
await fsPromises3.writeFile(rootPackagePath, JSON.stringify(pkg, null, 2), "utf8");
|
|
261
|
+
await runCommand("pnpm format", { cwd: projectPath });
|
|
262
|
+
}
|
|
263
|
+
async function runPrettierSetup(projectPath) {
|
|
264
|
+
const prettierPrompt = await promptPrettier();
|
|
265
|
+
handleCancel(prettierPrompt);
|
|
266
|
+
if (prettierPrompt) {
|
|
267
|
+
const s = spinner2();
|
|
268
|
+
console.log("\n");
|
|
269
|
+
s.start("Setting up Prettier auto-formatting...");
|
|
270
|
+
try {
|
|
271
|
+
await setupPrettier(projectPath);
|
|
272
|
+
s.stop(pc5.green("\u2714 Success: Prettier formatting configured"));
|
|
273
|
+
} catch (error) {
|
|
274
|
+
s.stop(pc5.red("\u2716 Failed: Prettier setup failed"));
|
|
275
|
+
console.error(pc5.red(`
|
|
276
|
+
Error details: ${error.message || error}`));
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
console.log("\n");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/tasks/git.ts
|
|
284
|
+
import { confirm as confirm2, spinner as spinner3 } from "@clack/prompts";
|
|
285
|
+
import pc6 from "picocolors";
|
|
286
|
+
import fsPromises4 from "fs/promises";
|
|
287
|
+
import path4 from "path";
|
|
288
|
+
async function promptGit() {
|
|
289
|
+
return await confirm2({
|
|
290
|
+
message: "Do you want to initialize a local Git repository?",
|
|
291
|
+
initialValue: true
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
async function gitInit(projectPath) {
|
|
295
|
+
await runCommand("git init", { cwd: projectPath, silent: true });
|
|
296
|
+
const gitignore = [
|
|
297
|
+
"# Dependency directories",
|
|
298
|
+
"node_modules/",
|
|
299
|
+
"jspm_packages/",
|
|
300
|
+
"web_modules/",
|
|
301
|
+
"",
|
|
302
|
+
"# Build and output outputs",
|
|
303
|
+
"dist/",
|
|
304
|
+
"build/",
|
|
305
|
+
".next/",
|
|
306
|
+
"out/",
|
|
307
|
+
".turbo/",
|
|
308
|
+
"",
|
|
309
|
+
"# Environments",
|
|
310
|
+
".env",
|
|
311
|
+
".env.local",
|
|
312
|
+
".env.development.local",
|
|
313
|
+
".env.test.local",
|
|
314
|
+
".env.production.local",
|
|
315
|
+
"",
|
|
316
|
+
"# Logs",
|
|
317
|
+
"npm-debug.log*",
|
|
318
|
+
"yarn-debug.log*",
|
|
319
|
+
"yarn-error.log*",
|
|
320
|
+
"pnpm-debug.log*",
|
|
321
|
+
"*.log",
|
|
322
|
+
"",
|
|
323
|
+
"# OS Metadata",
|
|
324
|
+
".DS_Store",
|
|
325
|
+
"Thumbs.db",
|
|
326
|
+
""
|
|
327
|
+
].join("\n");
|
|
328
|
+
await fsPromises4.writeFile(
|
|
329
|
+
path4.join(projectPath, ".gitignore"),
|
|
330
|
+
gitignore,
|
|
331
|
+
"utf8"
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
async function runGitSetup(projectPath) {
|
|
335
|
+
const gitPrompt = await promptGit();
|
|
336
|
+
handleCancel(gitPrompt);
|
|
337
|
+
let gitInitialized = false;
|
|
338
|
+
if (gitPrompt) {
|
|
339
|
+
const s = spinner3();
|
|
340
|
+
console.log("\n");
|
|
341
|
+
s.start("Initializing Git repository...");
|
|
342
|
+
try {
|
|
343
|
+
await gitInit(projectPath);
|
|
344
|
+
s.stop(pc6.green("\u2714 Success: Git repository initialized"));
|
|
345
|
+
gitInitialized = true;
|
|
346
|
+
} catch (error) {
|
|
347
|
+
s.stop(pc6.red("\u2716 Failed: Git initialization failed"));
|
|
348
|
+
console.error(pc6.red(`
|
|
349
|
+
Error details: ${error.message || error}`));
|
|
350
|
+
process.exit(1);
|
|
351
|
+
}
|
|
352
|
+
console.log("\n");
|
|
353
|
+
}
|
|
354
|
+
return gitInitialized;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/tasks/husky.ts
|
|
358
|
+
import { confirm as confirm3, spinner as spinner4 } from "@clack/prompts";
|
|
359
|
+
import pc7 from "picocolors";
|
|
360
|
+
import fsPromises5 from "fs/promises";
|
|
361
|
+
import path5 from "path";
|
|
362
|
+
async function promptHusky() {
|
|
363
|
+
return await confirm3({
|
|
364
|
+
message: "Do you want to setup Husky pre-commit hooks?",
|
|
365
|
+
initialValue: true
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
async function setupHusky(projectPath) {
|
|
369
|
+
await runCommand("pnpm add -D -E husky -w", { cwd: projectPath });
|
|
370
|
+
await runCommand("pnpm exec husky init", { cwd: projectPath });
|
|
371
|
+
const preCommitPath = path5.join(projectPath, ".husky", "pre-commit");
|
|
372
|
+
let hookContent = "";
|
|
373
|
+
try {
|
|
374
|
+
hookContent = await fsPromises5.readFile(preCommitPath, "utf8");
|
|
375
|
+
} catch {
|
|
376
|
+
hookContent = "pnpm test";
|
|
377
|
+
}
|
|
378
|
+
hookContent = hookContent.replace("pnpm test", "pnpm format");
|
|
379
|
+
if (!hookContent.includes("git add .")) {
|
|
380
|
+
hookContent = hookContent.trim() + "\ngit add .\n";
|
|
381
|
+
}
|
|
382
|
+
await fsPromises5.writeFile(preCommitPath, hookContent, "utf8");
|
|
383
|
+
try {
|
|
384
|
+
await fsPromises5.chmod(preCommitPath, 493);
|
|
385
|
+
} catch {
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async function runHuskySetup(projectPath, gitInitialized) {
|
|
389
|
+
if (!gitInitialized) return;
|
|
390
|
+
const huskyPrompt = await promptHusky();
|
|
391
|
+
handleCancel(huskyPrompt);
|
|
392
|
+
if (huskyPrompt) {
|
|
393
|
+
const s = spinner4();
|
|
394
|
+
console.log("\n");
|
|
395
|
+
s.start("Setting up Husky hooks...");
|
|
396
|
+
try {
|
|
397
|
+
await setupHusky(projectPath);
|
|
398
|
+
s.stop(pc7.green("\u2714 Success: Husky pre-commit hooks configured"));
|
|
399
|
+
} catch (error) {
|
|
400
|
+
s.stop(pc7.red("\u2716 Failed: Husky setup failed"));
|
|
401
|
+
console.error(pc7.red(`
|
|
402
|
+
Error details: ${error.message || error}`));
|
|
403
|
+
process.exit(1);
|
|
404
|
+
}
|
|
405
|
+
console.log("\n");
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// src/core/endcli.ts
|
|
410
|
+
import pc8 from "picocolors";
|
|
411
|
+
import { outro } from "@clack/prompts";
|
|
412
|
+
import boxen2 from "boxen";
|
|
413
|
+
function endCli(name, projectPath) {
|
|
414
|
+
outro(pc8.yellow("Morax scaffolding completed successfully!"));
|
|
415
|
+
console.log(
|
|
416
|
+
boxen2(
|
|
417
|
+
`\u26A1 ${pc8.bold("Workspace ready:")} ${pc8.yellow(name)}
|
|
418
|
+
Location: ${pc8.cyan(projectPath)}
|
|
419
|
+
|
|
420
|
+
${pc8.bold("To start developing:")}
|
|
421
|
+
1. ${pc8.cyan(`cd ${name}`)}
|
|
422
|
+
2. ${pc8.cyan("pnpm dev")}
|
|
423
|
+
|
|
424
|
+
\u{1F4A1} Code formatting & git orchestration is fully active.`,
|
|
425
|
+
{
|
|
426
|
+
padding: 0,
|
|
427
|
+
margin: 0,
|
|
428
|
+
borderStyle: "round",
|
|
429
|
+
borderColor: "yellow",
|
|
430
|
+
title: pc8.black(pc8.bold(" Setup Complete ")),
|
|
431
|
+
titleAlignment: "center"
|
|
432
|
+
}
|
|
433
|
+
)
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/core/runner.ts
|
|
438
|
+
async function runWorkspaceScaffolder() {
|
|
439
|
+
startCli();
|
|
440
|
+
const name = await promptWorkspaceName();
|
|
441
|
+
const projectPath = path6.join(process.cwd(), name);
|
|
442
|
+
await makeDirectories(name, projectPath);
|
|
443
|
+
const gitInitialized = await runGitSetup(projectPath);
|
|
444
|
+
await runPrettierSetup(projectPath);
|
|
445
|
+
await runHuskySetup(projectPath, gitInitialized);
|
|
446
|
+
endCli(name, projectPath);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/index.ts
|
|
450
|
+
async function main() {
|
|
451
|
+
await runWorkspaceScaffolder();
|
|
452
|
+
}
|
|
453
|
+
main().catch((err) => {
|
|
454
|
+
console.error(pc9.red("Fatal Error during execution:"), err);
|
|
455
|
+
process.exit(1);
|
|
456
|
+
});
|
|
457
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/runner.ts","../src/core/startcli.ts","../src/core/workspaceName.ts","../src/utils/isCancel.ts","../src/tasks/directories.ts","../src/tasks/workspace.ts","../src/utils/exec.ts","../src/tasks/prettier.ts","../src/tasks/git.ts","../src/tasks/husky.ts","../src/core/endcli.ts"],"sourcesContent":["import pc from 'picocolors';\nimport { runWorkspaceScaffolder } from './core/runner.js';\n\nasync function main() {\n await runWorkspaceScaffolder();\n}\n\nmain().catch((err) => {\n console.error(pc.red('Fatal Error during execution:'), err);\n process.exit(1);\n});\n","import path from 'path';\n\nimport { startCli } from './startcli.js';\nimport { promptWorkspaceName } from './workspaceName.js';\nimport { makeDirectories } from '../tasks/directories.js';\nimport { runPrettierSetup } from '../tasks/prettier.js';\nimport { runGitSetup } from '../tasks/git.js';\nimport { runHuskySetup } from '../tasks/husky.js';\nimport { endCli } from './endcli.js';\n\nexport async function runWorkspaceScaffolder() {\n // 1. Greet and display premium logo\n startCli();\n\n // 2. Prompt for Name (Optional, defaults to morax-workspace)\n const name = await promptWorkspaceName();\n const projectPath = path.join(process.cwd(), name);\n\n // 3. Prompt and execute directories and workspace config generation\n await makeDirectories(name, projectPath);\n\n // 4. Prompt and execute Git initialization\n const gitInitialized = await runGitSetup(projectPath);\n\n // 5. Prompt and execute Prettier setup\n await runPrettierSetup(projectPath);\n\n // 6. Prompt and execute Husky setup\n await runHuskySetup(projectPath, gitInitialized);\n\n // 7. Complete and show beautiful finish screen\n endCli(name, projectPath);\n}\n","import gradient from 'gradient-string';\nimport pc from 'picocolors';\nimport { intro } from '@clack/prompts';\nimport boxen from 'boxen';\n\nconst asciiArt = [\n \"███╗ ███╗ ██████╗ ██████╗ █████╗ ██╗ ██╗\",\n \"████╗ ████║ ██╔═══██╗ ██╔══██╗ ██╔══██╗ ╚██╗██╔╝\",\n \"██╔████╔██║ ██║ ██║ ██████╔╝ ███████║ ╚███╔╝ \",\n \"██║╚██╔╝██║ ██║ ██║ ██╔══██╗ ██╔══██║ ██╔██╗ \",\n \"██║ ╚═╝ ██║ ╚██████╔╝ ██║ ██║ ██║ ██║ ██╔╝ ██╗\",\n \"╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝\"\n].join('\\n');\n\nexport function startCli() {\n console.clear();\n\n // Premium fiery orange-to-yellow brand gradient\n const moraxGradient = gradient(['#FF3E00', '#FF8C00', '#FFAE19']);\n\n console.log('\\n');\n console.log(moraxGradient(asciiArt));\n console.log('\\n');\n\n intro(pc.yellow('🌌 Welcome to Morax — The Next-Gen Workspace Scaffolder'));\n\n console.log(\n boxen(\n `⚡ ${pc.bold('Morax')} automates the setup of modern ${pc.cyan('pnpm workspaces')}, linking internal shared configurations, UI packages, and framework apps concurrently.`,\n {\n padding: 1,\n margin: { top: 0, bottom: 1, left: 1, right: 1 },\n borderStyle: 'round',\n borderColor: 'yellow',\n }\n )\n );\n}\n","import { text } from '@clack/prompts';\nimport handleCancel from '../utils/isCancel.js';\n\nexport async function promptWorkspaceName(): Promise<string> {\n const nameInput = await text({\n message: 'What is the name of your new monorepo workspace?',\n placeholder: 'morax-workspace',\n validate(value) {\n if (value && value.includes(' ')) return 'Workspace name cannot contain spaces!';\n },\n });\n\n handleCancel(nameInput);\n\n // Fallback to morax-workspace if left blank\n return String(nameInput).trim() || 'morax-workspace';\n}\n","import { isCancel, cancel } from \"@clack/prompts\";\r\nimport pc from \"picocolors\";\r\n\r\nexport default function handleCancel(input:any) {\r\n if (isCancel(input)) {\r\n cancel(pc.red('✖ Morax cancelled.'));\r\n process.exit(0);\r\n }\r\n}","import { multiselect, spinner } from '@clack/prompts';\nimport fsPromises from 'fs/promises';\nimport path from 'path';\nimport pc from 'picocolors';\nimport handleCancel from '../utils/isCancel.js';\nimport { generateWorkspaceConfig } from './workspace.js';\n\nexport async function createDirectories(\n directories: ('apps' | 'packages')[],\n projectPath: string,\n) {\n for (const dir of directories) {\n const dirPath = path.join(projectPath, dir);\n await fsPromises.mkdir(dirPath, { recursive: true });\n await fsPromises.writeFile(\n path.join(dirPath, '.gitkeep'),\n `# Placeholder to ensure git tracks the empty ${dir}/ folder\\n`,\n 'utf8',\n );\n }\n}\n\nexport async function makeDirectories(name: string, projectPath: string) {\n const directories = await multiselect({\n message: 'Which directories do you want to include in your workspace?',\n options: [\n {\n value: 'apps',\n label: 'apps/*',\n hint: 'For frontend apps and backend services',\n },\n {\n value: 'packages',\n label: 'packages/*',\n hint: 'For shared components, configs, and utilities',\n },\n ],\n required: true,\n });\n\n handleCancel(directories);\n\n const s = spinner();\n console.log('\\n');\n s.start('Generating workspace configs...');\n try {\n await generateWorkspaceConfig(\n name,\n directories as ('apps' | 'packages')[],\n projectPath,\n );\n await createDirectories(\n directories as ('apps' | 'packages')[],\n projectPath,\n );\n s.stop(pc.green('✔ Success: Generated Workspace Root & Folder Structures'));\n } catch (error: any) {\n s.stop(pc.red('✖ Failed: Workspace generation failed'));\n console.error(pc.red(`\\nError details: ${error.message || error}`));\n process.exit(1);\n }\n console.log('\\n');\n\n return directories;\n}","import fsPromises from 'fs/promises';\nimport path from 'path';\nimport { runCommand } from '../utils/exec.js';\n\nexport async function generateWorkspaceConfig(\n name: string,\n directories: ('apps' | 'packages')[],\n projectPath: string,\n) {\n // 1. Create target folder if it doesn't exist\n await fsPromises.mkdir(projectPath, { recursive: true });\n\n // 2. Generate pnpm-workspace.yaml based on user's selective input\n const workspaceYamlContent = [\n 'packages:',\n ...directories.map((dir) => ` - '${dir}/*'`),\n '',\n ].join('\\n');\n\n await fsPromises.writeFile(\n path.join(projectPath, 'pnpm-workspace.yaml'),\n workspaceYamlContent,\n 'utf8',\n );\n\n // 3. Generate Root package.json using pnpm init\n await runCommand('pnpm init', { cwd: projectPath, silent: true });\n\n // 4. Read, parse and customize the package.json\n const packageJsonPath = path.join(projectPath, 'package.json');\n const packageJsonRaw = await fsPromises.readFile(packageJsonPath, 'utf8');\n const pkg = JSON.parse(packageJsonRaw);\n\n pkg.name = name;\n pkg.description = 'High-performance monorepo workspace generated by Morax';\n pkg.private = true;\n pkg.packageManager = 'pnpm@9.15.4';\n pkg.workspaces = directories.map((dir) => `${dir}/*`);\n pkg.scripts = {\n dev: 'pnpm --filter morax-web dev',\n };\n\n // Remove entry points since workspace root is private and has no main entry\n delete pkg.main;\n\n await fsPromises.writeFile(\n packageJsonPath,\n JSON.stringify(pkg, null, 2),\n 'utf8',\n );\n}\n\n","import { exec } from 'child_process';\nimport { promisify } from 'util';\nimport pc from 'picocolors';\n\nconst execAsync = promisify(exec);\n\nexport interface RunCommandOptions {\n cwd?: string;\n silent?: boolean;\n}\n\n/**\n * Reusable helper to execute commands and print/return their outputs\n */\nexport async function runCommand(command: string, options: RunCommandOptions = {}) {\n if (!options.silent) {\n console.log(pc.cyan(`> ${command}`));\n }\n \n try {\n const { stdout, stderr } = await execAsync(command, {\n cwd: options.cwd,\n env: { ...process.env, NODE_NO_WARNINGS: '1' },\n });\n \n if (!options.silent) {\n if (stdout && stdout.trim()) {\n console.log(stdout.trim());\n }\n if (stderr && stderr.trim()) {\n console.log(pc.yellow(stderr.trim()));\n }\n }\n \n return { stdout, stderr };\n } catch (error: any) {\n if (!options.silent) {\n if (error.stdout && error.stdout.trim()) {\n console.log(error.stdout.trim());\n }\n if (error.stderr && error.stderr.trim()) {\n console.error(pc.red(error.stderr.trim()));\n }\n }\n throw error;\n }\n}\n","import { confirm, spinner } from '@clack/prompts';\nimport pc from 'picocolors';\nimport handleCancel from '../utils/isCancel.js';\nimport fsPromises from 'fs/promises';\nimport path from 'path';\nimport { runCommand } from '../utils/exec.js';\n\nexport async function promptPrettier() {\n return await confirm({\n message: 'Do you want to setup Prettier code formatting?',\n initialValue: true,\n });\n}\n\nexport async function setupPrettier(projectPath: string) {\n // 1. Install Prettier dynamically with exact version at the workspace root\n await runCommand('pnpm add -D -E prettier -w', { cwd: projectPath });\n\n // 2. Create high-quality modern .prettierrc\n const prettierrc = {\n semi: true,\n singleQuote: true,\n tabWidth: 2,\n trailingComma: 'all',\n printWidth: 100,\n };\n\n await fsPromises.writeFile(\n path.join(projectPath, '.prettierrc'),\n JSON.stringify(prettierrc, null, 2),\n 'utf8',\n );\n\n // 3. Create comprehensive .prettierignore\n const prettierignore = [\n '# Dependencies',\n 'node_modules/',\n 'jspm_packages/',\n 'web_modules/',\n '',\n '# Build and outputs',\n 'dist/',\n 'build/',\n '.next/',\n 'out/',\n '.turbo/',\n '',\n '# Configuration locks',\n 'pnpm-lock.yaml',\n '',\n '# Environment files',\n '.env',\n '.env.*',\n '',\n ].join('\\n');\n\n await fsPromises.writeFile(\n path.join(projectPath, '.prettierignore'),\n prettierignore,\n 'utf8',\n );\n\n // 4. Inject format script to root package.json\n const rootPackagePath = path.join(projectPath, 'package.json');\n const rootPackageContent = await fsPromises.readFile(rootPackagePath, 'utf8');\n const pkg = JSON.parse(rootPackageContent);\n\n pkg.scripts = {\n ...(pkg.scripts || {}),\n format: 'prettier --write .',\n };\n\n await fsPromises.writeFile(rootPackagePath, JSON.stringify(pkg, null, 2), 'utf8');\n\n // 5. Initial format execution to clean up generated files\n await runCommand('pnpm format', { cwd: projectPath });\n}\n\nexport async function runPrettierSetup(projectPath: string) {\n const prettierPrompt = await promptPrettier();\n\n handleCancel(prettierPrompt);\n\n if (prettierPrompt) {\n const s = spinner();\n console.log('\\n');\n s.start('Setting up Prettier auto-formatting...');\n try {\n await setupPrettier(projectPath);\n s.stop(pc.green('✔ Success: Prettier formatting configured'));\n } catch (error: any) {\n s.stop(pc.red('✖ Failed: Prettier setup failed'));\n console.error(pc.red(`\\nError details: ${error.message || error}`));\n process.exit(1);\n }\n console.log('\\n');\n }\n}\n","import { confirm, spinner } from '@clack/prompts';\nimport pc from 'picocolors';\nimport handleCancel from '../utils/isCancel.js';\nimport fsPromises from 'fs/promises';\nimport path from 'path';\nimport { runCommand } from '../utils/exec.js';\n\nexport async function promptGit() {\n return await confirm({\n message: 'Do you want to initialize a local Git repository?',\n initialValue: true,\n });\n}\n\nexport async function gitInit(projectPath: string) {\n // 1. Initialize empty git repository\n await runCommand('git init', { cwd: projectPath, silent: true });\n\n // 2. Create high-quality standard .gitignore\n const gitignore = [\n '# Dependency directories',\n 'node_modules/',\n 'jspm_packages/',\n 'web_modules/',\n '',\n '# Build and output outputs',\n 'dist/',\n 'build/',\n '.next/',\n 'out/',\n '.turbo/',\n '',\n '# Environments',\n '.env',\n '.env.local',\n '.env.development.local',\n '.env.test.local',\n '.env.production.local',\n '',\n '# Logs',\n 'npm-debug.log*',\n 'yarn-debug.log*',\n 'yarn-error.log*',\n 'pnpm-debug.log*',\n '*.log',\n '',\n '# OS Metadata',\n '.DS_Store',\n 'Thumbs.db',\n '',\n ].join('\\n');\n\n await fsPromises.writeFile(\n path.join(projectPath, '.gitignore'),\n gitignore,\n 'utf8',\n );\n}\n\nexport async function runGitSetup(projectPath: string): Promise<boolean> {\n const gitPrompt = await promptGit();\n\n handleCancel(gitPrompt);\n\n let gitInitialized = false;\n if (gitPrompt) {\n const s = spinner();\n console.log('\\n');\n s.start('Initializing Git repository...');\n try {\n await gitInit(projectPath);\n s.stop(pc.green('✔ Success: Git repository initialized'));\n gitInitialized = true;\n } catch (error: any) {\n s.stop(pc.red('✖ Failed: Git initialization failed'));\n console.error(pc.red(`\\nError details: ${error.message || error}`));\n process.exit(1);\n }\n console.log('\\n');\n }\n return gitInitialized;\n}\n","import { confirm, spinner } from '@clack/prompts';\nimport pc from 'picocolors';\nimport handleCancel from '../utils/isCancel.js';\nimport fsPromises from 'fs/promises';\nimport path from 'path';\nimport { runCommand } from '../utils/exec.js';\n\nexport async function promptHusky() {\n return await confirm({\n message: 'Do you want to setup Husky pre-commit hooks?',\n initialValue: true,\n });\n}\n\nexport async function setupHusky(projectPath: string) {\n // 1. Install Husky dynamically with exact version at the workspace root\n await runCommand('pnpm add -D -E husky -w', { cwd: projectPath });\n\n // 2. Initialize Husky using its official init generator\n await runCommand('pnpm exec husky init', { cwd: projectPath });\n\n // 3. Update the auto-generated .husky/pre-commit file to run format and stage files\n const preCommitPath = path.join(projectPath, '.husky', 'pre-commit');\n let hookContent = '';\n try {\n hookContent = await fsPromises.readFile(preCommitPath, 'utf8');\n } catch {\n hookContent = 'pnpm test'; // Default fallback\n }\n\n // Replace default test commands with formatting checks\n hookContent = hookContent\n .replace('pnpm test', 'pnpm format')\n\n // Append staging of newly formatted files\n if (!hookContent.includes('git add .')) {\n hookContent = hookContent.trim() + '\\ngit add .\\n';\n }\n\n await fsPromises.writeFile(preCommitPath, hookContent, 'utf8');\n\n try {\n await fsPromises.chmod(preCommitPath, 0o755);\n } catch { }\n}\n\nexport async function runHuskySetup(projectPath: string, gitInitialized: boolean) {\n if (!gitInitialized) return;\n\n const huskyPrompt = await promptHusky();\n\n handleCancel(huskyPrompt);\n\n if (huskyPrompt) {\n const s = spinner();\n console.log('\\n');\n s.start('Setting up Husky hooks...');\n try {\n await setupHusky(projectPath);\n s.stop(pc.green('✔ Success: Husky pre-commit hooks configured'));\n } catch (error: any) {\n s.stop(pc.red('✖ Failed: Husky setup failed'));\n console.error(pc.red(`\\nError details: ${error.message || error}`));\n process.exit(1);\n }\n console.log('\\n');\n }\n}\n","import pc from 'picocolors';\nimport { outro } from '@clack/prompts';\nimport boxen from 'boxen';\n\nexport function endCli(name: string, projectPath: string) {\n // Complete and show beautiful finish screen\n outro(pc.yellow('Morax scaffolding completed successfully!'));\n\n console.log(\n boxen(\n `⚡ ${pc.bold('Workspace ready:')} ${pc.yellow(name)}\\n` +\n `Location: ${pc.cyan(projectPath)}\\n\\n` +\n `${pc.bold('To start developing:')}\\n` +\n ` 1. ${pc.cyan(`cd ${name}`)}\\n` +\n ` 2. ${pc.cyan('pnpm dev')}\\n\\n` +\n `💡 Code formatting & git orchestration is fully active.`,\n {\n padding: 0,\n margin: 0,\n borderStyle: 'round',\n borderColor: 'yellow',\n title: pc.black(pc.bold(' Setup Complete ')),\n titleAlignment: 'center',\n },\n ),\n );\n}\n"],"mappings":"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","names":["pc","path","pc","fsPromises","path","pc","pc","path","fsPromises","pc","spinner","pc","fsPromises","path","fsPromises","path","spinner","pc","confirm","spinner","pc","fsPromises","path","confirm","fsPromises","path","spinner","pc","confirm","spinner","pc","fsPromises","path","confirm","path","fsPromises","spinner","pc","pc","boxen","path","pc"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-morax",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "Ashutosh",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"bin": {
|
|
9
|
+
"create-morax": "dist/index.js",
|
|
10
|
+
"morax": "dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev": "npx tsx src/index.ts",
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"start": "node dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@clack/prompts": "^1.3.0",
|
|
22
|
+
"boxen": "^8.0.1",
|
|
23
|
+
"gradient-string": "^3.0.0",
|
|
24
|
+
"ora": "^9.4.0",
|
|
25
|
+
"picocolors": "^1.1.1"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/gradient-string": "^1.1.6",
|
|
29
|
+
"@types/node": "^24.0.0",
|
|
30
|
+
"tsup": "^8.5.0",
|
|
31
|
+
"tsx": "^4.20.0",
|
|
32
|
+
"typescript": "^5.8.3"
|
|
33
|
+
}
|
|
34
|
+
}
|