create-gm-app 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gilbert Munuo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # create-gm-app
2
+
3
+ ๐Ÿš€ A professional CLI tool to scaffold modern **Web** and **Mobile** applications with a clean, production-ready setup.
4
+
5
+ ---
6
+
7
+ ## โœจ Features
8
+
9
+ * โšก Fast project scaffolding using **npx**
10
+ * ๐ŸŒ Web stack (Next.js + Tailwind + shadcn/ui)
11
+ * ๐Ÿ“ฑ Mobile stack (Expo + HeroUI + Uniwind)
12
+ * ๐Ÿง  Smart interactive CLI (Inquirer-based)
13
+ * ๐Ÿงน Clean project structure out of the box
14
+ * ๐Ÿ”ง Minimal but scalable architecture
15
+ * ๐Ÿงฉ Built for extensibility (future stacks)
16
+
17
+ ---
18
+
19
+ ## ๐Ÿ“ฆ Installation (No global install required)
20
+
21
+ ```bash
22
+ npx create-gm-app
23
+ ```
24
+
25
+ Or specify directly:
26
+
27
+ ```bash
28
+ npx create-gm-app web my-app
29
+ npx create-gm-app mobile my-app
30
+ ```
31
+
32
+ ---
33
+
34
+ ## ๐Ÿงฑ Supported Stacks
35
+
36
+ ### ๐ŸŒ Web Stack
37
+
38
+ * Next.js (App Router)
39
+ * TypeScript
40
+ * Tailwind CSS
41
+ * shadcn/ui
42
+ * ESLint
43
+ * React Compiler (enabled)
44
+
45
+ #### Optional Customization
46
+
47
+ * `src/` directory
48
+ * Import alias (`@/*`)
49
+ * AGENTS.md support
50
+
51
+ ---
52
+
53
+ ### ๐Ÿ“ฑ Mobile Stack
54
+
55
+ * Expo (latest)
56
+ * TypeScript
57
+ * HeroUI Native
58
+ * Uniwind (Tailwind for React Native)
59
+ * React Native Reanimated
60
+ * Gesture Handler
61
+
62
+ #### Includes
63
+
64
+ * Clean folder structure:
65
+
66
+ ```
67
+ app/
68
+ components/
69
+ lib/
70
+ hooks/
71
+ ```
72
+ * Babel configured for Reanimated
73
+ * Reset of default Expo boilerplate
74
+
75
+ ---
76
+
77
+ ## ๐Ÿง‘โ€๐Ÿ’ป Usage
78
+
79
+ ### Interactive Mode
80
+
81
+ ```bash
82
+ npx create-gm-app
83
+ ```
84
+
85
+ Youโ€™ll be prompted to choose:
86
+
87
+ * Project type (Web / Mobile)
88
+ * Project name
89
+ * Customization options
90
+
91
+ ---
92
+
93
+ ### Direct Mode
94
+
95
+ ```bash
96
+ npx create-gm-app web my-app
97
+ npx create-gm-app mobile my-app
98
+ ```
99
+
100
+ ---
101
+
102
+ ## ๐Ÿ“ Project Structure (CLI)
103
+
104
+ ```
105
+ gm-stack/
106
+ โ”œโ”€โ”€ bin/ # CLI entry
107
+ โ”œโ”€โ”€ src/
108
+ โ”‚ โ”œโ”€โ”€ cli/ # CLI logic
109
+ โ”‚ โ”œโ”€โ”€ commands/ # Commands (create, etc.)
110
+ โ”‚ โ”œโ”€โ”€ templates/ # Web & Mobile templates
111
+ โ”‚ โ””โ”€โ”€ utils/ # Helpers (validation, etc.)
112
+ ```
113
+
114
+ ---
115
+
116
+ ## ๐Ÿ› ๏ธ Development
117
+
118
+ Clone the repo:
119
+
120
+ ```bash
121
+ git clone https://github.com/your-username/gm-stack.git
122
+ cd gm-stack
123
+ npm install
124
+ ```
125
+
126
+ Run locally:
127
+
128
+ ```bash
129
+ npm link
130
+ npm run build
131
+ npx create-gm-app
132
+ ```
133
+
134
+ ---
135
+
136
+ ## ๐Ÿ“Œ Roadmap
137
+
138
+ * [ ] More templates (e.g., SaaS starter, dashboard)
139
+ * [ ] Plugin system
140
+ * [ ] Config file support (`gm.config.json`)
141
+ * [ ] CI/CD presets
142
+ * [ ] Database integrations (Prisma, Supabase)
143
+
144
+ ---
145
+
146
+ ## ๐Ÿค Contributing
147
+
148
+ Contributions are welcome. Feel free to open issues or submit PRs.
149
+
150
+ ---
151
+
152
+ ## ๐Ÿ“„ License
153
+
154
+ MIT License
155
+
156
+ ---
157
+
158
+ ## ๐Ÿ‘ค Author
159
+
160
+ **Gilbert Munuo**
161
+ Aspiring Software Developer | Builder of scalable developer tools
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import('../dist/cli/index.js');
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,36 @@
1
+ import { Command } from "commander";
2
+ import { createApp } from "../commands/create.js";
3
+ import inquirer from "inquirer";
4
+ const program = new Command();
5
+ program
6
+ .name("create-gm-app")
7
+ .description("CLI to scaffold GM Stack apps")
8
+ .version("1.0.0")
9
+ .arguments("[type] [name]")
10
+ .action(async (_type, _name) => {
11
+ const answers = await inquirer.prompt([
12
+ {
13
+ type: "select",
14
+ name: "type",
15
+ message: "What do you want to build?",
16
+ choices: [
17
+ { name: "๐ŸŒ Web", value: "web" },
18
+ { name: "๐Ÿ“ฑ Mobile", value: "mobile" },
19
+ ],
20
+ default: "web",
21
+ when: !_type // Only prompt if type not supplied
22
+ },
23
+ {
24
+ type: "input",
25
+ name: "name",
26
+ message: "Project name:",
27
+ validate: (input) => input && !input.includes(" ") ? true : "Invalid project name",
28
+ when: !_name // Only prompt if name not supplied
29
+ }
30
+ ]);
31
+ const projectType = (_type || answers.type).toLowerCase();
32
+ const projectName = (_name || answers.name).trim().toLowerCase().replace(/\s+/g, "-");
33
+ await createApp(projectType, projectName);
34
+ });
35
+ program.parse();
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,eAAe,CAAC;KACrB,WAAW,CAAC,+BAA+B,CAAC;KAC5C,OAAO,CAAC,OAAO,CAAC;KAChB,SAAS,CAAC,eAAe,CAAC;KAC1B,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAC7B,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QACpC;YACE,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,4BAA4B;YACrC,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE;gBAChC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE;aACvC;YACD,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,CAAC,KAAK,CAAC,mCAAmC;SACjD;QACD;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,eAAe;YACxB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,sBAAsB;YAC/D,IAAI,EAAE,CAAC,KAAK,CAAC,mCAAmC;SACjD;KACF,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1D,MAAM,WAAW,GAAG,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEtF,MAAM,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAC5C,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function createApp(type: string, name: string): Promise<void>;
2
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAGA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iBAUzD"}
@@ -0,0 +1,16 @@
1
+ import { createMobileApp } from "../templates/mobile/config.js";
2
+ import { createWebApp } from "../templates/web/config.js";
3
+ export async function createApp(type, name) {
4
+ type = type.toLowerCase();
5
+ if (type === "web") {
6
+ await createWebApp(name);
7
+ }
8
+ else if (type === "mobile") {
9
+ await createMobileApp(name);
10
+ }
11
+ else {
12
+ console.error("โŒ Invalid type: use 'mobile' or 'web'");
13
+ process.exit(1);
14
+ }
15
+ }
16
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,IAAY;IACtD,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAC1B,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACjB,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;SAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;SAAM,CAAC;QACJ,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function createMobileApp(name: string): Promise<void>;
2
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/templates/mobile/config.ts"],"names":[],"mappings":"AAMA,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,iBAoHjD"}
@@ -0,0 +1,92 @@
1
+ import { execa } from "execa";
2
+ import fs from "fs-extra";
3
+ import path from "path";
4
+ import { validateProjectName } from "../../utils/validate.js";
5
+ import ora from "ora";
6
+ export async function createMobileApp(name) {
7
+ const spinner = ora();
8
+ name = validateProjectName(name);
9
+ const projectPath = path.join(process.cwd(), name);
10
+ // Step 1: Create Expo project
11
+ spinner.start("๐Ÿš€ Creating Expo app...");
12
+ await execa("npx", ["create-expo-app@latest", name], {
13
+ stdio: "inherit",
14
+ });
15
+ spinner.succeed("Expo app created");
16
+ // Step 2: Reset project directories
17
+ spinner.start("๐Ÿงน Resetting project structure...");
18
+ const dirsToRemove = ["app", "components", "hooks", "constants", "scripts"];
19
+ for (const dir of dirsToRemove) {
20
+ const targetPath = path.join(projectPath, dir);
21
+ if (await fs.pathExists(targetPath)) {
22
+ await fs.remove(targetPath);
23
+ }
24
+ }
25
+ spinner.succeed("Project cleaned");
26
+ // Create new /app folder with index.tsx and _layout.tsx
27
+ const appDir = path.join(projectPath, "app");
28
+ await fs.ensureDir(appDir);
29
+ await fs.writeFile(path.join(appDir, "index.tsx"), `import { Text, View } from 'react-native';
30
+
31
+ export default function RootLayout() {
32
+ return (
33
+ <View className="flex-1 items-center justify-center">
34
+ <Text>Hello, Expo + GM Stack!</Text>
35
+ </View>
36
+ );
37
+ }
38
+ `);
39
+ await fs.writeFile(path.join(appDir, "_layout.tsx"), ` import { Stack } from "expo-router";
40
+
41
+ export default function RootLayout() {
42
+ return <Stack />;
43
+ }
44
+ `);
45
+ spinner.succeed("Project structure reset");
46
+ // Step 3: Install dependencies
47
+ spinner.start("๐Ÿ“ฆ Installing dependencies...");
48
+ await execa("npm", ["install", "heroui-native", "react-native-svg", "tailwind-variants", "tailwind-merge", "uniwind"], { cwd: projectPath, stdio: "inherit" });
49
+ spinner.succeed("Dependencies installed");
50
+ // Step 4: Create global.css file and Import it in main component file(rootLayout.tsx)
51
+ spinner.start("โŒ›๏ธ Creating global.css file...;");
52
+ await fs.writeFile(path.join(projectPath, "global.css"), `
53
+ @import 'tailwindcss';
54
+ @import 'uniwind';
55
+ @import 'heroui-native/styles';
56
+
57
+ @source './node_modules/heroui-native/lib';
58
+ `);
59
+ await fs.writeFile(path.join(projectPath, "app", "_layout.tsx"), `
60
+ import '../global.css';
61
+ import { Slot } from "expo-router";
62
+
63
+ export default function RootLayout() {
64
+ return <Slot />;
65
+ }
66
+ `);
67
+ // Step 5: Create metro.config.js file and add the following code
68
+ spinner.start("โš™๏ธ creating metro.config.js...");
69
+ await fs.writeFile(path.join(projectPath, "metro.config.js"), `
70
+ // Learn more https://docs.expo.io/guides/customizing-metro
71
+ const { getDefaultConfig } = require('expo/metro-config');
72
+ const { withUniwindConfig } = require('uniwind/metro');
73
+
74
+ /** @type {import('expo/metro-config').MetroConfig} */
75
+ const config = getDefaultConfig(__dirname);
76
+
77
+ module.exports = withUniwindConfig(config, {
78
+ cssEntryFile: './global.css',
79
+ dtsFile: './uniwind-types.d.ts'
80
+ });
81
+ `);
82
+ spinner.succeed("Metro config created");
83
+ // Step 6: Ensure folder structure
84
+ spinner.start("๐Ÿ“ Creating folders...");
85
+ const dirs = ["components", "lib", "hooks", "constants", "config", "library", "providers", "utils"];
86
+ for (const dir of dirs) {
87
+ await fs.ensureDir(path.join(projectPath, dir));
88
+ }
89
+ spinner.succeed("Folder structure ready");
90
+ console.log(`\nโœ… Mobile app "${name}" is ready!\n`);
91
+ }
92
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/templates/mobile/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function createWebApp(name: string): Promise<void>;
2
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/templates/web/config.ts"],"names":[],"mappings":"AAKA,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,iBAoF9C"}
@@ -0,0 +1,80 @@
1
+ import { execa } from "execa";
2
+ import path from "path";
3
+ import ora from "ora";
4
+ import inquirer from "inquirer";
5
+ export async function createWebApp(name) {
6
+ const spinner = ora();
7
+ const projectPath = path.join(process.cwd(), name);
8
+ // Step 1: Ask if user wants to customize certain options
9
+ const { customize } = await inquirer.prompt([
10
+ {
11
+ type: "select",
12
+ name: "customize",
13
+ message: "Would you like to customize your app?",
14
+ choices: [
15
+ { name: "Yes, customize settings", value: true },
16
+ { name: "No, use recommended defaults", value: false },
17
+ ],
18
+ default: true,
19
+ },
20
+ ]);
21
+ // Step 2: Ask only customizable options if user chooses to customize
22
+ let options = {};
23
+ if (customize) {
24
+ options = await inquirer.prompt([
25
+ {
26
+ type: "confirm",
27
+ name: "srcDir",
28
+ message: "Would you like your code inside a `src/` directory?",
29
+ default: true,
30
+ },
31
+ {
32
+ type: "confirm",
33
+ name: "agentsMd",
34
+ message: "Include AGENTS.md to guide coding agents?",
35
+ default: false,
36
+ },
37
+ {
38
+ type: "confirm",
39
+ name: "importAlias",
40
+ message: "Use import alias: @/*",
41
+ default: false,
42
+ },
43
+ ]);
44
+ }
45
+ // Step 3: Build args for create-next-app
46
+ const args = [
47
+ "--yes",
48
+ "create-next-app@latest",
49
+ name,
50
+ "--ts", // forced Yes
51
+ "--eslint", // forced Yes
52
+ "--react-compiler", // forced Yes
53
+ "--tailwind", // forced Yes
54
+ "--app", // App Router forced Yes
55
+ options.srcDir ? "--src-dir" : "--no-src-dir",
56
+ options.agentsMd ? "--agents-md" : "--no-agents-md",
57
+ "--import-alias",
58
+ options.importAlias || "@/*",
59
+ ];
60
+ // Step 4: Run create-next-app
61
+ spinner.start("Creating Next.js app...");
62
+ await execa("npx", args, { stdio: "inherit" });
63
+ spinner.succeed("Next.js app created");
64
+ // Step 5: Setup shadcn
65
+ spinner.start("Setting up shadcn...");
66
+ try {
67
+ await execa("npx", ["shadcn@latest", "init"], {
68
+ cwd: projectPath,
69
+ stdio: "inherit",
70
+ });
71
+ spinner.succeed("shadcn configured");
72
+ console.log(`\n๐ŸŽ‰ Web app "${name}" is ready!\n`);
73
+ }
74
+ catch (error) {
75
+ spinner.fail("Failed to setup shadcn");
76
+ console.error(error);
77
+ process.exit(1);
78
+ }
79
+ }
80
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/templates/web/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC;IACtB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;IAEnD,yDAAyD;IACzD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QAC1C;YACE,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,uCAAuC;YAChD,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,yBAAyB,EAAE,KAAK,EAAE,IAAI,EAAE;gBAChD,EAAE,IAAI,EAAE,8BAA8B,EAAE,KAAK,EAAE,KAAK,EAAE;aACvD;YACD,OAAO,EAAE,IAAI;SACd;KACF,CAAC,CAAC;IAEH,qEAAqE;IACrE,IAAI,OAAO,GAIP,EAAE,CAAC;IAEP,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YAC9B;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,qDAAqD;gBAC9D,OAAO,EAAE,IAAI;aACd;YACD;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,2CAA2C;gBACpD,OAAO,EAAE,KAAK;aACf;YACD;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,uBAAuB;gBAChC,OAAO,EAAE,KAAK;aACf;SACF,CAAC,CAAC;IACL,CAAC;IAED,yCAAyC;IACzC,MAAM,IAAI,GAAa;QACrB,OAAO;QACP,wBAAwB;QACxB,IAAI;QACJ,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,aAAa;QACzB,kBAAkB,EAAE,aAAa;QACjC,YAAY,EAAE,aAAa;QAC3B,OAAO,EAAE,wBAAwB;QACjC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;QAC7C,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB;QACnD,gBAAgB;QAChB,OAAO,CAAC,WAAW,IAAI,KAAK;KAC7B,CAAC;IAEF,8BAA8B;IAC9B,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACzC,MAAM,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAEvC,uBAAuB;IACvB,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,eAAe,EAAE,MAAM,CAAC,EAAE;YAC5C,GAAG,EAAE,WAAW;YAChB,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;QACH,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAErC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,eAAe,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QACvC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function validateProjectName(name: string): string;
2
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,UAM/C"}
@@ -0,0 +1,8 @@
1
+ export function validateProjectName(name) {
2
+ if (!name || name.includes(" ")) {
3
+ console.error("โŒ Invalid project name");
4
+ process.exit(1);
5
+ }
6
+ return name;
7
+ }
8
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC5C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "create-gm-app",
3
+ "version": "1.0.0",
4
+ "description": "Official CLI to scaffold GM Stack apps",
5
+ "bin": {
6
+ "create-gm-app": "./bin/create-gm-stack.js"
7
+ },
8
+ "main": "index.js",
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "prepublishOnly": "npm run build",
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "files": [
15
+ "bin",
16
+ "dist"
17
+ ],
18
+ "keywords": [
19
+ "cli",
20
+ "scaffold",
21
+ "expo",
22
+ "nextjs"
23
+ ],
24
+ "author": "Gilbert Munuo",
25
+ "license": "MIT",
26
+ "type": "module",
27
+ "dependencies": {
28
+ "chalk": "^5.6.2",
29
+ "commander": "^14.0.3",
30
+ "execa": "^9.6.1",
31
+ "fs-extra": "^11.3.4",
32
+ "inquirer": "^13.3.2",
33
+ "ora": "^9.3.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/fs-extra": "^11.0.4",
37
+ "@types/node": "^25.5.2",
38
+ "ts-node": "^10.9.2",
39
+ "typescript": "^6.0.2"
40
+ }
41
+ }