create-habeetat 0.1.0-dev.20260323164114.3a5aac3

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 ADDED
@@ -0,0 +1,67 @@
1
+ # create-habeetat
2
+
3
+ Create a new Habeetat Platform instance with a single command.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npm create habeetat my-platform
9
+ ```
10
+
11
+ Or with a specific version:
12
+
13
+ ```bash
14
+ npm create habeetat@dev my-platform
15
+ ```
16
+
17
+ ## What it does
18
+
19
+ 1. Checks prerequisites (Docker, Node.js)
20
+ 2. Prompts for configuration (domain, admin email, password, organization)
21
+ 3. Scaffolds a project directory with all necessary files
22
+ 4. Generates Docker Compose, Nginx, and environment configuration
23
+
24
+ ## Options
25
+
26
+ ```bash
27
+ npm create habeetat [name] [options]
28
+
29
+ Options:
30
+ --domain <domain> Domain name (e.g., example.com)
31
+ --admin-email <email> Admin email
32
+ --admin-password <password> Admin password
33
+ --organization <name> Organization name
34
+ --no-ssl Disable SSL (HTTPS)
35
+ --skip-start Don't start after scaffolding
36
+ --tag <tag> Docker image tag (default: CLI version)
37
+ ```
38
+
39
+ ## Generated Project
40
+
41
+ ```
42
+ my-platform/
43
+ habeetat.json # Platform configuration
44
+ .env # Environment variables (secrets)
45
+ docker-compose.yml # Docker service definitions
46
+ nginx/platform.conf # Nginx reverse proxy config
47
+ package.json # With @habeetat/cli dependency
48
+ README.md
49
+ ```
50
+
51
+ ## After Creation
52
+
53
+ ```bash
54
+ cd my-platform
55
+ npx habeetat up # Start the platform
56
+ npx habeetat status # Check service health
57
+ npx habeetat logs -f # Follow logs
58
+ ```
59
+
60
+ ## Requirements
61
+
62
+ - Docker >= 20.0 with Compose V2
63
+ - Node.js >= 18
64
+
65
+ ## License
66
+
67
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,266 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var commander = require('commander');
5
+ var inquirer = require('inquirer');
6
+ var chalk = require('chalk');
7
+ var ora = require('ora');
8
+ var fs = require('fs');
9
+ var path = require('path');
10
+ var cli = require('@habeetat/cli');
11
+
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
+
14
+ var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
15
+ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
16
+ var ora__default = /*#__PURE__*/_interopDefault(ora);
17
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
18
+ var path__default = /*#__PURE__*/_interopDefault(path);
19
+
20
+ var pkg = JSON.parse(
21
+ fs__default.default.readFileSync(path__default.default.resolve(__dirname, "..", "package.json"), "utf-8")
22
+ );
23
+ var program = new commander.Command();
24
+ program.name("create-habeetat").description("Create a new Habeetat Platform instance").version(pkg.version).argument("[name]", "Project directory name").option("--domain <domain>", "Domain name").option("--admin-email <email>", "Admin email").option("--admin-password <password>", "Admin password").option("--organization <name>", "Organization name").option("--no-ssl", "Disable SSL").option("--skip-start", "Skip starting the platform after scaffolding").option("--tag <tag>", "Docker image tag to use", pkg.version).action(async (name, options) => {
25
+ await create(name, options);
26
+ });
27
+ program.parse();
28
+ async function create(nameArg, cliOptions) {
29
+ console.log("");
30
+ console.log(chalk__default.default.cyan("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
31
+ console.log(chalk__default.default.cyan("\u2551 \u2551"));
32
+ console.log(chalk__default.default.cyan("\u2551 Create Habeetat Platform \u2551"));
33
+ console.log(chalk__default.default.cyan("\u2551 \u2551"));
34
+ console.log(chalk__default.default.cyan("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
35
+ console.log("");
36
+ cli.logger.info("Checking prerequisites...");
37
+ if (!await cli.checkPrerequisites()) {
38
+ process.exit(1);
39
+ }
40
+ cli.logger.success("Prerequisites OK");
41
+ console.log("");
42
+ let projectName = nameArg;
43
+ if (!projectName) {
44
+ const answer = await inquirer__default.default.prompt([
45
+ {
46
+ type: "input",
47
+ name: "name",
48
+ message: "Project name:",
49
+ default: "my-platform",
50
+ validate: (input) => {
51
+ if (/^[a-z0-9][a-z0-9-]*$/.test(input)) return true;
52
+ return "Name must be lowercase alphanumeric with dashes";
53
+ }
54
+ }
55
+ ]);
56
+ projectName = answer.name;
57
+ }
58
+ const projectDir = path__default.default.resolve(process.cwd(), projectName);
59
+ if (fs__default.default.existsSync(projectDir)) {
60
+ const { overwrite } = await inquirer__default.default.prompt([
61
+ {
62
+ type: "confirm",
63
+ name: "overwrite",
64
+ message: `Directory ${projectName} already exists. Overwrite?`,
65
+ default: false
66
+ }
67
+ ]);
68
+ if (!overwrite) {
69
+ cli.logger.info("Aborted");
70
+ process.exit(0);
71
+ }
72
+ }
73
+ const answers = await inquirer__default.default.prompt(
74
+ [
75
+ !cliOptions.domain && {
76
+ type: "input",
77
+ name: "domain",
78
+ message: "Domain name (e.g., example.com):",
79
+ validate: (input) => {
80
+ if (/^[a-z0-9]([a-z0-9-]*\.)+[a-z]{2,}$/.test(input) || input.endsWith(".nip.io")) return true;
81
+ return "Enter a valid domain name";
82
+ }
83
+ },
84
+ !cliOptions.adminEmail && {
85
+ type: "input",
86
+ name: "adminEmail",
87
+ message: "Admin email:",
88
+ validate: (input) => {
89
+ if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input)) return true;
90
+ return "Enter a valid email address";
91
+ }
92
+ },
93
+ !cliOptions.adminPassword && {
94
+ type: "password",
95
+ name: "adminPassword",
96
+ message: "Admin password:",
97
+ mask: "*",
98
+ validate: (input) => {
99
+ if (input.length >= 8) return true;
100
+ return "Password must be at least 8 characters";
101
+ }
102
+ },
103
+ !cliOptions.organization && {
104
+ type: "input",
105
+ name: "organizationName",
106
+ message: "Organization name:",
107
+ validate: (input) => {
108
+ if (input.trim().length > 0) return true;
109
+ return "Organization name is required";
110
+ }
111
+ },
112
+ cliOptions.ssl === void 0 && {
113
+ type: "confirm",
114
+ name: "ssl",
115
+ message: "Enable SSL (HTTPS)?",
116
+ default: true
117
+ }
118
+ ].filter(Boolean)
119
+ );
120
+ const opts = {
121
+ domain: cliOptions.domain || answers.domain,
122
+ adminEmail: cliOptions.adminEmail || answers.adminEmail,
123
+ adminPassword: cliOptions.adminPassword || answers.adminPassword,
124
+ organizationName: cliOptions.organization || answers.organizationName,
125
+ ssl: cliOptions.ssl !== void 0 ? cliOptions.ssl : answers.ssl,
126
+ tag: cliOptions.tag || pkg.version,
127
+ skipStart: cliOptions.skipStart || false
128
+ };
129
+ const config = {
130
+ version: pkg.version,
131
+ platform: {
132
+ domain: opts.domain,
133
+ protocol: opts.ssl ? "https" : "http",
134
+ organization: opts.organizationName,
135
+ adminEmail: opts.adminEmail
136
+ },
137
+ docker: {
138
+ registry: cli.DOCKER_REGISTRY,
139
+ imageTag: opts.tag
140
+ },
141
+ services: {
142
+ backend: true,
143
+ launcher: true,
144
+ organizationManager: true,
145
+ platformManager: true,
146
+ sampleCrm: false
147
+ }
148
+ };
149
+ cli.logger.phase("Scaffolding project...");
150
+ const spinner = ora__default.default("Creating project directory...").start();
151
+ fs__default.default.mkdirSync(path__default.default.join(projectDir, "nginx"), { recursive: true });
152
+ if (opts.ssl) {
153
+ fs__default.default.mkdirSync(path__default.default.join(projectDir, "certbot", "conf"), { recursive: true });
154
+ fs__default.default.mkdirSync(path__default.default.join(projectDir, "certbot", "www"), { recursive: true });
155
+ }
156
+ spinner.text = "Generating configuration files...";
157
+ fs__default.default.writeFileSync(
158
+ path__default.default.join(projectDir, cli.CONFIG_FILE),
159
+ JSON.stringify(config, null, 2) + "\n"
160
+ );
161
+ fs__default.default.writeFileSync(path__default.default.join(projectDir, cli.ENV_FILE), cli.generateEnvFile(opts));
162
+ fs__default.default.writeFileSync(path__default.default.join(projectDir, cli.COMPOSE_FILE), cli.generateDockerCompose(config));
163
+ fs__default.default.writeFileSync(
164
+ path__default.default.join(projectDir, "nginx", "platform.conf"),
165
+ cli.generateNginxConf(config)
166
+ );
167
+ fs__default.default.writeFileSync(
168
+ path__default.default.join(projectDir, ".gitignore"),
169
+ `.env
170
+ certbot/
171
+ *.log
172
+ `
173
+ );
174
+ fs__default.default.writeFileSync(
175
+ path__default.default.join(projectDir, "package.json"),
176
+ JSON.stringify(
177
+ {
178
+ name: projectName,
179
+ version: "1.0.0",
180
+ private: true,
181
+ description: `Habeetat Platform instance \u2014 ${opts.domain}`,
182
+ scripts: {
183
+ up: "habeetat up",
184
+ down: "habeetat down",
185
+ status: "habeetat status",
186
+ logs: "habeetat logs",
187
+ restart: "habeetat restart",
188
+ doctor: "habeetat doctor"
189
+ },
190
+ dependencies: {
191
+ "@habeetat/cli": `^${pkg.version}`
192
+ }
193
+ },
194
+ null,
195
+ 2
196
+ ) + "\n"
197
+ );
198
+ const proto = config.platform.protocol;
199
+ const domain = config.platform.domain;
200
+ fs__default.default.writeFileSync(
201
+ path__default.default.join(projectDir, "README.md"),
202
+ `# ${opts.organizationName} \u2014 Habeetat Platform
203
+
204
+ ## Quick Start
205
+
206
+ \`\`\`bash
207
+ cd ${projectName}
208
+ npx habeetat up
209
+ \`\`\`
210
+
211
+ ## Service URLs
212
+
213
+ | Service | URL |
214
+ |---|---|
215
+ | Launcher | ${proto}://launcher.${domain} |
216
+ | Organization Manager | ${proto}://organization-manager.${domain} |
217
+ | Platform Manager | ${proto}://platform-manager.${domain} |
218
+ | Backend API | ${proto}://api.${domain} |
219
+ | Logto IAM | ${proto}://iam.${domain} |
220
+ | Logto Admin Console | ${proto}://iam-console.${domain} |
221
+
222
+ ## Commands
223
+
224
+ \`\`\`bash
225
+ habeetat up # Start the platform
226
+ habeetat down # Stop the platform
227
+ habeetat status # Show service status
228
+ habeetat logs # View logs (add -f to follow)
229
+ habeetat restart # Restart all services
230
+ habeetat doctor # Diagnose issues
231
+ \`\`\`
232
+
233
+ ## Configuration
234
+
235
+ - \`habeetat.json\` \u2014 Platform configuration
236
+ - \`.env\` \u2014 Environment variables (secrets, passwords)
237
+ - \`docker-compose.yml\` \u2014 Docker service definitions
238
+ - \`nginx/platform.conf\` \u2014 Nginx reverse proxy configuration
239
+ `
240
+ );
241
+ spinner.succeed("Project scaffolded");
242
+ console.log("");
243
+ console.log(chalk__default.default.green("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
244
+ console.log(chalk__default.default.green("\u2551 \u2551"));
245
+ console.log(chalk__default.default.green("\u2551 Platform created successfully! \u2551"));
246
+ console.log(chalk__default.default.green("\u2551 \u2551"));
247
+ console.log(chalk__default.default.green("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
248
+ console.log("");
249
+ console.log(` ${chalk__default.default.bold("Directory:")} ${projectDir}`);
250
+ console.log(` ${chalk__default.default.bold("Domain:")} ${domain}`);
251
+ console.log(` ${chalk__default.default.bold("Protocol:")} ${proto}`);
252
+ console.log(` ${chalk__default.default.bold("Admin:")} ${opts.adminEmail}`);
253
+ console.log(` ${chalk__default.default.bold("Org:")} ${opts.organizationName}`);
254
+ console.log(` ${chalk__default.default.bold("Version:")} ${config.version}`);
255
+ console.log("");
256
+ if (!opts.skipStart) {
257
+ console.log(chalk__default.default.cyan("Next steps:"));
258
+ console.log(` cd ${projectName}`);
259
+ console.log(" npx habeetat up");
260
+ console.log("");
261
+ cli.logger.info("Note: Docker images will be pulled on first start (~2-3 min)");
262
+ }
263
+ console.log("");
264
+ }
265
+ //# sourceMappingURL=index.js.map
266
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["fs","path","Command","chalk","logger","checkPrerequisites","inquirer","DOCKER_REGISTRY","ora","CONFIG_FILE","ENV_FILE","generateEnvFile","COMPOSE_FILE","generateDockerCompose","generateNginxConf"],"mappings":"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","file":"index.js","sourcesContent":["import { Command } from 'commander';\nimport inquirer from 'inquirer';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport {\n generateDockerCompose,\n generateNginxConf,\n generateEnvFile,\n checkPrerequisites,\n logger,\n CONFIG_FILE,\n COMPOSE_FILE,\n ENV_FILE,\n DOCKER_REGISTRY,\n type HabeetatConfig,\n type CreateOptions,\n} from '@habeetat/cli';\n\nconst pkg = JSON.parse(\n fs.readFileSync(path.resolve(__dirname, '..', 'package.json'), 'utf-8'),\n);\n\nconst program = new Command();\n\nprogram\n .name('create-habeetat')\n .description('Create a new Habeetat Platform instance')\n .version(pkg.version)\n .argument('[name]', 'Project directory name')\n .option('--domain <domain>', 'Domain name')\n .option('--admin-email <email>', 'Admin email')\n .option('--admin-password <password>', 'Admin password')\n .option('--organization <name>', 'Organization name')\n .option('--no-ssl', 'Disable SSL')\n .option('--skip-start', 'Skip starting the platform after scaffolding')\n .option('--tag <tag>', 'Docker image tag to use', pkg.version)\n .action(async (name: string | undefined, options: Record<string, unknown>) => {\n await create(name, options);\n });\n\nprogram.parse();\n\nasync function create(\n nameArg: string | undefined,\n cliOptions: Record<string, unknown>,\n): Promise<void> {\n console.log('');\n console.log(chalk.cyan('╔══════════════════════════════════════════════╗'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('║ Create Habeetat Platform ║'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('╚══════════════════════════════════════════════╝'));\n console.log('');\n\n // Check prerequisites\n logger.info('Checking prerequisites...');\n if (!(await checkPrerequisites())) {\n process.exit(1);\n }\n logger.success('Prerequisites OK');\n console.log('');\n\n // Determine project name\n let projectName = nameArg;\n if (!projectName) {\n const answer = await inquirer.prompt([\n {\n type: 'input',\n name: 'name',\n message: 'Project name:',\n default: 'my-platform',\n validate: (input: string) => {\n if (/^[a-z0-9][a-z0-9-]*$/.test(input)) return true;\n return 'Name must be lowercase alphanumeric with dashes';\n },\n },\n ]);\n projectName = answer.name;\n }\n\n const projectDir = path.resolve(process.cwd(), projectName!);\n\n if (fs.existsSync(projectDir)) {\n const { overwrite } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'overwrite',\n message: `Directory ${projectName} already exists. Overwrite?`,\n default: false,\n },\n ]);\n if (!overwrite) {\n logger.info('Aborted');\n process.exit(0);\n }\n }\n\n // Interactive prompts for missing options\n const answers = await inquirer.prompt(\n [\n !cliOptions.domain && {\n type: 'input',\n name: 'domain',\n message: 'Domain name (e.g., example.com):',\n validate: (input: string) => {\n if (/^[a-z0-9]([a-z0-9-]*\\.)+[a-z]{2,}$/.test(input) || input.endsWith('.nip.io')) return true;\n return 'Enter a valid domain name';\n },\n },\n !cliOptions.adminEmail && {\n type: 'input',\n name: 'adminEmail',\n message: 'Admin email:',\n validate: (input: string) => {\n if (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(input)) return true;\n return 'Enter a valid email address';\n },\n },\n !cliOptions.adminPassword && {\n type: 'password',\n name: 'adminPassword',\n message: 'Admin password:',\n mask: '*',\n validate: (input: string) => {\n if (input.length >= 8) return true;\n return 'Password must be at least 8 characters';\n },\n },\n !cliOptions.organization && {\n type: 'input',\n name: 'organizationName',\n message: 'Organization name:',\n validate: (input: string) => {\n if (input.trim().length > 0) return true;\n return 'Organization name is required';\n },\n },\n cliOptions.ssl === undefined && {\n type: 'confirm',\n name: 'ssl',\n message: 'Enable SSL (HTTPS)?',\n default: true,\n },\n ].filter(Boolean),\n );\n\n const opts: CreateOptions = {\n domain: (cliOptions.domain as string) || answers.domain,\n adminEmail: (cliOptions.adminEmail as string) || answers.adminEmail,\n adminPassword: (cliOptions.adminPassword as string) || answers.adminPassword,\n organizationName: (cliOptions.organization as string) || answers.organizationName,\n ssl: cliOptions.ssl !== undefined ? (cliOptions.ssl as boolean) : answers.ssl,\n tag: (cliOptions.tag as string) || pkg.version,\n skipStart: (cliOptions.skipStart as boolean) || false,\n };\n\n // Build config\n const config: HabeetatConfig = {\n version: pkg.version,\n platform: {\n domain: opts.domain,\n protocol: opts.ssl ? 'https' : 'http',\n organization: opts.organizationName,\n adminEmail: opts.adminEmail,\n },\n docker: {\n registry: DOCKER_REGISTRY,\n imageTag: opts.tag,\n },\n services: {\n backend: true,\n launcher: true,\n organizationManager: true,\n platformManager: true,\n sampleCrm: false,\n },\n };\n\n // Scaffold project\n logger.phase('Scaffolding project...');\n\n const spinner = ora('Creating project directory...').start();\n\n // Create directories\n fs.mkdirSync(path.join(projectDir, 'nginx'), { recursive: true });\n if (opts.ssl) {\n fs.mkdirSync(path.join(projectDir, 'certbot', 'conf'), { recursive: true });\n fs.mkdirSync(path.join(projectDir, 'certbot', 'www'), { recursive: true });\n }\n\n spinner.text = 'Generating configuration files...';\n\n // Write habeetat.json\n fs.writeFileSync(\n path.join(projectDir, CONFIG_FILE),\n JSON.stringify(config, null, 2) + '\\n',\n );\n\n // Write .env\n fs.writeFileSync(path.join(projectDir, ENV_FILE), generateEnvFile(opts));\n\n // Write docker-compose.yml\n fs.writeFileSync(path.join(projectDir, COMPOSE_FILE), generateDockerCompose(config));\n\n // Write nginx config\n fs.writeFileSync(\n path.join(projectDir, 'nginx', 'platform.conf'),\n generateNginxConf(config),\n );\n\n // Write .gitignore\n fs.writeFileSync(\n path.join(projectDir, '.gitignore'),\n `.env\ncertbot/\n*.log\n`,\n );\n\n // Write package.json for the project (so habeetat CLI can be a local dep)\n fs.writeFileSync(\n path.join(projectDir, 'package.json'),\n JSON.stringify(\n {\n name: projectName,\n version: '1.0.0',\n private: true,\n description: `Habeetat Platform instance — ${opts.domain}`,\n scripts: {\n up: 'habeetat up',\n down: 'habeetat down',\n status: 'habeetat status',\n logs: 'habeetat logs',\n restart: 'habeetat restart',\n doctor: 'habeetat doctor',\n },\n dependencies: {\n '@habeetat/cli': `^${pkg.version}`,\n },\n },\n null,\n 2,\n ) + '\\n',\n );\n\n // Write README\n const proto = config.platform.protocol;\n const domain = config.platform.domain;\n fs.writeFileSync(\n path.join(projectDir, 'README.md'),\n `# ${opts.organizationName} — Habeetat Platform\n\n## Quick Start\n\n\\`\\`\\`bash\ncd ${projectName}\nnpx habeetat up\n\\`\\`\\`\n\n## Service URLs\n\n| Service | URL |\n|---|---|\n| Launcher | ${proto}://launcher.${domain} |\n| Organization Manager | ${proto}://organization-manager.${domain} |\n| Platform Manager | ${proto}://platform-manager.${domain} |\n| Backend API | ${proto}://api.${domain} |\n| Logto IAM | ${proto}://iam.${domain} |\n| Logto Admin Console | ${proto}://iam-console.${domain} |\n\n## Commands\n\n\\`\\`\\`bash\nhabeetat up # Start the platform\nhabeetat down # Stop the platform\nhabeetat status # Show service status\nhabeetat logs # View logs (add -f to follow)\nhabeetat restart # Restart all services\nhabeetat doctor # Diagnose issues\n\\`\\`\\`\n\n## Configuration\n\n- \\`habeetat.json\\` — Platform configuration\n- \\`.env\\` — Environment variables (secrets, passwords)\n- \\`docker-compose.yml\\` — Docker service definitions\n- \\`nginx/platform.conf\\` — Nginx reverse proxy configuration\n`,\n );\n\n spinner.succeed('Project scaffolded');\n\n // Summary\n console.log('');\n console.log(chalk.green('╔══════════════════════════════════════════════╗'));\n console.log(chalk.green('║ ║'));\n console.log(chalk.green('║ Platform created successfully! ║'));\n console.log(chalk.green('║ ║'));\n console.log(chalk.green('╚══════════════════════════════════════════════╝'));\n console.log('');\n console.log(` ${chalk.bold('Directory:')} ${projectDir}`);\n console.log(` ${chalk.bold('Domain:')} ${domain}`);\n console.log(` ${chalk.bold('Protocol:')} ${proto}`);\n console.log(` ${chalk.bold('Admin:')} ${opts.adminEmail}`);\n console.log(` ${chalk.bold('Org:')} ${opts.organizationName}`);\n console.log(` ${chalk.bold('Version:')} ${config.version}`);\n console.log('');\n\n if (!opts.skipStart) {\n console.log(chalk.cyan('Next steps:'));\n console.log(` cd ${projectName}`);\n console.log(' npx habeetat up');\n console.log('');\n logger.info('Note: Docker images will be pulled on first start (~2-3 min)');\n }\n\n console.log('');\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "create-habeetat",
3
+ "version": "0.1.0-dev.20260323164114.3a5aac3",
4
+ "description": "Create a new Habeetat Platform instance",
5
+ "main": "./dist/index.js",
6
+ "bin": {
7
+ "create-habeetat": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsup",
14
+ "dev": "tsup --watch",
15
+ "typecheck": "tsc --noEmit",
16
+ "clean": "rm -rf dist"
17
+ },
18
+ "dependencies": {
19
+ "@habeetat/cli": "0.1.0-dev.20260323164114.3a5aac3",
20
+ "chalk": "^5.3.0",
21
+ "commander": "^12.1.0",
22
+ "inquirer": "^9.2.0",
23
+ "ora": "^8.0.1"
24
+ },
25
+ "devDependencies": {
26
+ "@types/inquirer": "^9.0.0",
27
+ "@types/node": "^20.0.0",
28
+ "tsup": "^8.0.0",
29
+ "typescript": "^5.3.0"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://bitbucket.org/habeetat/nhp.git",
37
+ "directory": "packages/create-habeetat"
38
+ },
39
+ "license": "MIT",
40
+ "keywords": [
41
+ "habeetat",
42
+ "create",
43
+ "platform",
44
+ "cli",
45
+ "docker"
46
+ ],
47
+ "engines": {
48
+ "node": ">=18.0.0"
49
+ }
50
+ }