@cruxgarden/cli 0.0.9 → 0.0.10

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 CHANGED
@@ -57,7 +57,7 @@ Start the Nursery environment:
57
57
  crux nursery start
58
58
  ```
59
59
 
60
- The API will be available at `http://localhost:3000` with demo data loaded.
60
+ The App will be available at `http://localhost:8080` and the API at `http://localhost:3000` with demo data loaded.
61
61
 
62
62
  View logs:
63
63
 
@@ -77,15 +77,26 @@ All commands are scoped under `crux nursery`:
77
77
 
78
78
  ### `crux nursery start`
79
79
 
80
- Start the Nursery environment (PostgreSQL, Redis, Migrations, and API with demo data).
80
+ Start the Nursery environment (App, API, PostgreSQL, Redis with demo data).
81
81
 
82
82
  ```bash
83
83
  crux nursery start
84
+
85
+ # With inline environment variables
86
+ crux nursery start API_PORT=3001 APP_PORT=8081
87
+
88
+ # With options and environment variables
89
+ crux nursery start --api-only JWT_SECRET=my-secret
84
90
  ```
85
91
 
86
92
  **Options:**
87
93
 
88
94
  - `--db-only` - Start only database services (PostgreSQL and Redis)
95
+ - `--api-only` - Start only API services (API, PostgreSQL, Redis) without the App
96
+
97
+ **Environment Variables:**
98
+
99
+ You can pass environment variables directly on the command line in `KEY=VALUE` format after the command and options. These override values from your `.env` file.
89
100
 
90
101
  ### `crux nursery stop`
91
102
 
@@ -103,6 +114,11 @@ Restart the Nursery environment.
103
114
  crux nursery restart
104
115
  ```
105
116
 
117
+ **Options:**
118
+
119
+ - `--db-only` - Restart only database services (PostgreSQL and Redis)
120
+ - `--api-only` - Restart only API services (API, PostgreSQL, Redis) without the App
121
+
106
122
  ### `crux nursery status`
107
123
 
108
124
  Show the status of all Nursery services.
@@ -198,6 +214,14 @@ Connect to Nursery Redis with `redis-cli`.
198
214
  crux nursery redis connect
199
215
  ```
200
216
 
217
+ ### `crux nursery api start`
218
+
219
+ Start only Nursery API services (API, PostgreSQL, Redis) without the App.
220
+
221
+ ```bash
222
+ crux nursery api start
223
+ ```
224
+
201
225
  ### `crux nursery api connect`
202
226
 
203
227
  Open a shell in the Nursery API container.
@@ -217,31 +241,81 @@ The Nursery is a production-like demo environment that:
217
241
 
218
242
  **Services:**
219
243
 
244
+ - **App**: `http://localhost:8080` - Crux Garden Web Application
220
245
  - **API**: `http://localhost:3000` - Crux Garden API (published image with demo data)
221
246
  - **PostgreSQL**: `localhost:5432` - Database
222
247
  - **Redis**: `localhost:6379` - Cache
223
248
 
224
249
  ## Environment Variables
225
250
 
226
- The Nursery environment has defaults for all environment variables, so a `.env` file is optional. However, you can override any variable by creating a `.env` file in your working directory:
251
+ The Nursery environment has defaults for all environment variables, so configuration is optional. You can override variables in two ways:
252
+
253
+ ### 1. Using a `.env` file
254
+
255
+ Create a `.env` file in your working directory:
227
256
 
228
257
  ```bash
229
- # JWT (has dev default, but you should use a different one)
258
+ # Port Mappings
259
+ API_PORT=3000 # External API port
260
+ APP_PORT=8080 # External App port
261
+ POSTGRES_PORT=5432 # External PostgreSQL port
262
+ REDIS_PORT=6379 # External Redis port
263
+
264
+ # PostgreSQL Configuration
265
+ POSTGRES_DB=cruxgarden
266
+ POSTGRES_USER=cruxgarden
267
+ POSTGRES_PASSWORD=cruxgarden_nursery_password
268
+
269
+ # Database & Cache URLs (override to use external services)
270
+ DATABASE_URL=postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden
271
+ REDIS_URL=redis://redis:6379
272
+
273
+ # Security (has dev default, but you should use a different one)
230
274
  JWT_SECRET=your-super-secret-jwt-key-min-32-chars
231
275
 
232
- # AWS (defaults to "dummy" values)
276
+ # AWS Configuration (defaults to "dummy" values)
233
277
  AWS_ACCESS_KEY_ID=your-key
234
278
  AWS_SECRET_ACCESS_KEY=your-secret
235
279
  AWS_REGION=us-east-1
236
280
  AWS_SES_FROM_EMAIL=demo@example.com
237
281
  AWS_S3_ATTACHMENTS_BUCKET=crux-garden-attachments
238
282
 
239
- # Optional overrides
283
+ # Optional Configuration
284
+ NODE_ENV=production
240
285
  CORS_ORIGIN=*
241
286
  LOG_LEVEL=info
242
- PORT=3000
287
+ HOSTNAME=0.0.0.0
288
+ DB_POOL_MIN=2
289
+ DB_POOL_MAX=10
290
+ DB_POOL_IDLE_TIMEOUT=30000
291
+ DB_POOL_ACQUIRE_TIMEOUT=60000
292
+ RATE_LIMIT_TTL=60000
293
+ RATE_LIMIT_MAX=100
243
294
  ```
244
295
 
296
+ ### 2. Using inline environment variables
297
+
298
+ Pass environment variables directly on the command line:
299
+
300
+ ```bash
301
+ # Override ports
302
+ crux nursery start API_PORT=3001 APP_PORT=8081
303
+
304
+ # Override database connection
305
+ crux nursery start DATABASE_URL=postgresql://user:pass@external-host:5432/db
306
+
307
+ # Multiple variables
308
+ crux nursery start API_PORT=3001 JWT_SECRET=my-secret AWS_REGION=us-west-2
309
+
310
+ # Works with all start commands
311
+ crux nursery api start API_PORT=4000
312
+ crux nursery db start POSTGRES_PORT=5433
313
+ crux nursery restart API_PORT=3001
314
+ crux nursery reset JWT_SECRET=new-secret
315
+ ```
316
+
317
+ **Note:** Inline environment variables override values from your `.env` file. You can override `DATABASE_URL` and `REDIS_URL` to connect the API to external database/cache services instead of the bundled ones.
318
+
245
319
  ## Common Workflows
246
320
 
247
321
  ### Demo/Trial Setup
@@ -249,10 +323,11 @@ PORT=3000
249
323
  Use the Nursery environment for demos, trials, or showcasing features:
250
324
 
251
325
  ```bash
252
- # First time setup - pulls image and starts with demo data
326
+ # First time setup - pulls images and starts with demo data
253
327
  crux nursery start
254
328
 
255
- # View the demo at http://localhost:3000
329
+ # View the app at http://localhost:8080
330
+ # Or access the API directly at http://localhost:3000
256
331
 
257
332
  # Stop (keeps data for next demo)
258
333
  crux nursery stop
@@ -304,6 +379,7 @@ If you get an error about ports being in use, stop any existing services:
304
379
 
305
380
  ```bash
306
381
  # Check what's using the ports
382
+ lsof -i :8080 # Nursery App
307
383
  lsof -i :3000 # Nursery API
308
384
  lsof -i :5432 # Nursery PostgreSQL
309
385
  lsof -i :6379 # Nursery Redis
package/bin/crux.js CHANGED
@@ -37,13 +37,14 @@ const nursery = program
37
37
  .description("Manage the Nursery environment (demo/trial environment)");
38
38
 
39
39
  nursery
40
- .command("start")
41
- .description("Start the Nursery environment (api, postgres, redis)")
40
+ .command("start [env...]")
41
+ .description("Start the Nursery environment (app, api, postgres, redis)")
42
42
  .option("--db-only", "Start only database services (postgres, redis)")
43
+ .option("--api-only", "Start only API services (api, postgres, redis) without app")
43
44
  .option("--no-banner", "Hide the startup banner")
44
- .action((options) => {
45
+ .action((envVars, options) => {
45
46
  if (!options.noBanner) showBanner();
46
- startNursery(options);
47
+ startNursery(options, envVars);
47
48
  });
48
49
 
49
50
  nursery
@@ -52,9 +53,11 @@ nursery
52
53
  .action(stopNursery);
53
54
 
54
55
  nursery
55
- .command("restart")
56
+ .command("restart [env...]")
56
57
  .description("Restart the Nursery environment")
57
- .action(restartNursery);
58
+ .option("--db-only", "Restart only database services (postgres, redis)")
59
+ .option("--api-only", "Restart only API services (api, postgres, redis) without app")
60
+ .action((envVars, options) => restartNursery(options, envVars));
58
61
 
59
62
  nursery
60
63
  .command("status")
@@ -85,7 +88,7 @@ nursery
85
88
  .action(updateNursery);
86
89
 
87
90
  nursery
88
- .command("reset")
91
+ .command("reset [env...]")
89
92
  .description("Complete fresh reset (stop, clean, pull latest image, restart)")
90
93
  .action(resetNursery);
91
94
 
@@ -95,9 +98,9 @@ const nurseryDb = nursery
95
98
  .description("Manage Nursery database services");
96
99
 
97
100
  nurseryDb
98
- .command("start")
101
+ .command("start [env...]")
99
102
  .description("Start only Nursery database services (postgres, redis)")
100
- .action(() => startNursery({ dbOnly: true }));
103
+ .action((envVars) => startNursery({ dbOnly: true }, envVars));
101
104
 
102
105
  nurseryDb
103
106
  .command("stop")
@@ -122,6 +125,11 @@ nurseryRedis
122
125
  // Nursery API commands
123
126
  const nurseryApi = nursery.command("api").description("Manage Nursery API");
124
127
 
128
+ nurseryApi
129
+ .command("start [env...]")
130
+ .description("Start only Nursery API services (api, postgres, redis) without app")
131
+ .action((envVars) => startNursery({ apiOnly: true }, envVars));
132
+
125
133
  nurseryApi
126
134
  .command("connect")
127
135
  .description("Open a shell in the Nursery API container")
@@ -12,15 +12,15 @@ services:
12
12
  image: postgres:16-alpine
13
13
  container_name: cruxgarden-nursery-postgres
14
14
  environment:
15
- POSTGRES_DB: cruxgarden
16
- POSTGRES_USER: cruxgarden
17
- POSTGRES_PASSWORD: cruxgarden_nursery_password
15
+ POSTGRES_DB: ${POSTGRES_DB:-cruxgarden}
16
+ POSTGRES_USER: ${POSTGRES_USER:-cruxgarden}
17
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-cruxgarden_nursery_password}
18
18
  ports:
19
- - "5432:5432"
19
+ - "${POSTGRES_PORT:-5432}:5432"
20
20
  volumes:
21
21
  - postgres_data_nursery:/var/lib/postgresql/data
22
22
  healthcheck:
23
- test: ["CMD-SHELL", "pg_isready -U cruxgarden"]
23
+ test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-cruxgarden}"]
24
24
  interval: 5s
25
25
  timeout: 5s
26
26
  retries: 5
@@ -31,7 +31,7 @@ services:
31
31
  container_name: cruxgarden-nursery-redis
32
32
  command: redis-server --appendonly yes
33
33
  ports:
34
- - "6379:6379"
34
+ - "${REDIS_PORT:-6379}:6379"
35
35
  volumes:
36
36
  - redis_data_nursery:/data
37
37
  healthcheck:
@@ -48,8 +48,8 @@ services:
48
48
  postgres:
49
49
  condition: service_healthy
50
50
  environment:
51
- NODE_ENV: production
52
- DATABASE_URL: postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden
51
+ NODE_ENV: ${NODE_ENV:-production}
52
+ DATABASE_URL: ${DATABASE_URL:-postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden}
53
53
  command: ["npm", "run", "migrate:nursery"]
54
54
  restart: "no"
55
55
 
@@ -64,16 +64,16 @@ services:
64
64
  redis:
65
65
  condition: service_healthy
66
66
  ports:
67
- - "${PORT:-3000}:3000"
67
+ - "${API_PORT:-3000}:3000"
68
68
  environment:
69
69
  # Application
70
- NODE_ENV: production
70
+ NODE_ENV: ${NODE_ENV:-production}
71
71
  PORT: 3000
72
- HOSTNAME: 0.0.0.0
72
+ HOSTNAME: ${HOSTNAME:-0.0.0.0}
73
73
 
74
- # Bundled Services
75
- DATABASE_URL: postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden
76
- REDIS_URL: redis://redis:6379
74
+ # Bundled Services (can override to use external services)
75
+ DATABASE_URL: ${DATABASE_URL:-postgresql://cruxgarden:cruxgarden_nursery_password@postgres:5432/cruxgarden}
76
+ REDIS_URL: ${REDIS_URL:-redis://redis:6379}
77
77
 
78
78
  # Security
79
79
  JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-key-min-32-chars-for-development-only}
@@ -107,6 +107,17 @@ services:
107
107
  retries: 3
108
108
  start_period: 40s
109
109
 
110
+ # Crux Garden App - Web Application
111
+ app:
112
+ image: ghcr.io/cruxgarden/app:latest
113
+ container_name: cruxgarden-nursery-app
114
+ restart: unless-stopped
115
+ depends_on:
116
+ api:
117
+ condition: service_healthy
118
+ ports:
119
+ - "${APP_PORT:-8080}:80"
120
+
110
121
  volumes:
111
122
  postgres_data_nursery:
112
123
  redis_data_nursery:
package/lib/commands.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { execSync, spawn } from "child_process";
2
2
  import { fileURLToPath } from "url";
3
3
  import { dirname, join } from "path";
4
- import { readFileSync } from "fs";
4
+ import { readFileSync, existsSync } from "fs";
5
5
  import readline from "readline";
6
6
  import chalk from "chalk";
7
7
  import ora from "ora";
@@ -166,35 +166,110 @@ function ensureDockerRunning() {
166
166
  }
167
167
  }
168
168
 
169
+ function getEnvFileFlag() {
170
+ const envFilePath = join(process.cwd(), ".env");
171
+ if (existsSync(envFilePath)) {
172
+ return `--env-file "${envFilePath}"`;
173
+ }
174
+ return "";
175
+ }
176
+
177
+ function parseAndSetEnvVars(envArgs = []) {
178
+ if (!envArgs || envArgs.length === 0) return;
179
+
180
+ for (const arg of envArgs) {
181
+ const match = arg.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
182
+ if (match) {
183
+ const [, key, value] = match;
184
+ process.env[key] = value;
185
+ console.log(chalk.gray(` Setting ${key}=${value}`));
186
+ } else {
187
+ console.log(chalk.yellow(` Warning: Ignoring invalid env var format: ${arg}`));
188
+ }
189
+ }
190
+ }
191
+
169
192
  // ============================================================================
170
193
  // Nursery Environment Commands
171
194
  // ============================================================================
172
195
 
173
- export async function startNursery(options) {
196
+ export async function startNursery(options, envVars) {
174
197
  ensureDockerRunning();
198
+
199
+ // Parse and set environment variables from command line
200
+ if (envVars && envVars.length > 0) {
201
+ console.log(chalk.cyan("\nApplying environment variables:"));
202
+ parseAndSetEnvVars(envVars);
203
+ console.log();
204
+ }
205
+
175
206
  const spinner = ora("Starting Crux Garden Nursery environment...").start();
207
+ const envFileFlag = getEnvFileFlag();
208
+
209
+ // Get actual port values from environment
210
+ const appPort = process.env.APP_PORT || "8080";
211
+ const apiPort = process.env.API_PORT || "3000";
212
+ const postgresPort = process.env.POSTGRES_PORT || "5432";
213
+ const redisPort = process.env.REDIS_PORT || "6379";
176
214
 
177
215
  try {
178
216
  if (options.dbOnly) {
179
217
  spinner.text = "Starting nursery database services (postgres, redis)...";
180
218
  await runCommandAsync(
181
- "docker-compose -f docker-compose.nursery.yml up -d --remove-orphans postgres redis",
219
+ `docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans postgres redis`,
182
220
  { silent: true },
183
221
  );
184
222
  spinner.succeed("Nursery database services started!");
185
223
  console.log(
186
224
  chalk.hex(SUCCESS_GREEN)("\n✓ PostgreSQL running on:"),
187
- "localhost:5432",
225
+ `localhost:${postgresPort}`,
226
+ );
227
+ console.log(
228
+ chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
229
+ `localhost:${redisPort}`,
230
+ );
231
+ } else if (options.apiOnly) {
232
+ spinner.text =
233
+ "Starting nursery API services (api, postgres, redis)...";
234
+ await runCommandAsync(
235
+ `docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans postgres redis migrations api`,
236
+ {
237
+ silent: true,
238
+ },
239
+ );
240
+
241
+ // Clean up the migrations container if it exists (cross-platform)
242
+ await runCommandAsync(
243
+ "docker rm cruxgarden-nursery-migrations",
244
+ {
245
+ silent: true,
246
+ ignoreError: true,
247
+ },
248
+ );
249
+
250
+ spinner.succeed("Crux Garden Nursery API services started!");
251
+ console.log(
252
+ chalk.hex(SUCCESS_GREEN)("\n✓ API running on:"),
253
+ `http://localhost:${apiPort}`,
254
+ );
255
+ console.log(
256
+ chalk.hex(SUCCESS_GREEN)("✓ PostgreSQL running on:"),
257
+ `localhost:${postgresPort}`,
188
258
  );
189
259
  console.log(
190
260
  chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
191
- "localhost:6379",
261
+ `localhost:${redisPort}`,
262
+ );
263
+ console.log(
264
+ chalk.yellow(
265
+ "\nℹ Nursery includes demo data for trials and showcases",
266
+ ),
192
267
  );
193
268
  } else {
194
269
  spinner.text =
195
- "Starting nursery services (api, postgres, redis)...";
270
+ "Starting nursery services (app, api, postgres, redis)...";
196
271
  await runCommandAsync(
197
- "docker-compose -f docker-compose.nursery.yml up -d --remove-orphans",
272
+ `docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans`,
198
273
  {
199
274
  silent: true,
200
275
  },
@@ -211,16 +286,20 @@ export async function startNursery(options) {
211
286
 
212
287
  spinner.succeed("Crux Garden Nursery environment started!");
213
288
  console.log(
214
- chalk.hex(SUCCESS_GREEN)("\n✓ API running on:"),
215
- "http://localhost:3000",
289
+ chalk.hex(SUCCESS_GREEN)("\n✓ App running on:"),
290
+ `http://localhost:${appPort}`,
291
+ );
292
+ console.log(
293
+ chalk.hex(SUCCESS_GREEN)("✓ API running on:"),
294
+ `http://localhost:${apiPort}`,
216
295
  );
217
296
  console.log(
218
297
  chalk.hex(SUCCESS_GREEN)("✓ PostgreSQL running on:"),
219
- "localhost:5432",
298
+ `localhost:${postgresPort}`,
220
299
  );
221
300
  console.log(
222
301
  chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
223
- "localhost:6379",
302
+ `localhost:${redisPort}`,
224
303
  );
225
304
  console.log(
226
305
  chalk.yellow(
@@ -259,7 +338,8 @@ export async function startNursery(options) {
259
338
  export async function stopNursery() {
260
339
  ensureDockerRunning();
261
340
  const spinner = ora("Stopping Crux Garden Nursery environment...").start();
262
- await runCommandAsync("docker-compose -f docker-compose.nursery.yml down", {
341
+ const envFileFlag = getEnvFileFlag();
342
+ await runCommandAsync(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml down`, {
263
343
  silent: true,
264
344
  });
265
345
  spinner.succeed("Crux Garden Nursery environment stopped!");
@@ -273,13 +353,16 @@ export async function stopNursery() {
273
353
 
274
354
  export async function logsNursery(options) {
275
355
  ensureDockerRunning();
356
+ const envFileFlag = getEnvFileFlag();
357
+ const envFileArgs = envFileFlag ? envFileFlag.split(" ") : [];
358
+
276
359
  if (options.follow) {
277
360
  console.log(
278
361
  chalk.gray("Following nursery logs (press Ctrl+C to exit)...\n"),
279
362
  );
280
363
  const child = spawn(
281
364
  "docker-compose",
282
- ["-f", "docker-compose.nursery.yml", "logs", "-f"],
365
+ [...envFileArgs, "-f", "docker-compose.nursery.yml", "logs", "-f"],
283
366
  {
284
367
  cwd: dockerDir,
285
368
  stdio: "inherit",
@@ -291,7 +374,7 @@ export async function logsNursery(options) {
291
374
  process.exit(0);
292
375
  });
293
376
  } else {
294
- runCommand("docker-compose -f docker-compose.nursery.yml logs --tail=100");
377
+ runCommand(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml logs --tail=100`);
295
378
  console.log();
296
379
  }
297
380
  }
@@ -316,9 +399,10 @@ export async function cleanNursery() {
316
399
  const spinner = ora(
317
400
  "Cleaning up nursery (removing containers and volumes)...",
318
401
  ).start();
402
+ const envFileFlag = getEnvFileFlag();
319
403
 
320
404
  await runCommandAsync(
321
- "docker-compose -f docker-compose.nursery.yml down -v",
405
+ `docker-compose ${envFileFlag} -f docker-compose.nursery.yml down -v`,
322
406
  {
323
407
  silent: true,
324
408
  ignoreError: true,
@@ -359,9 +443,10 @@ export async function purgeNursery() {
359
443
  const spinner = ora(
360
444
  "Purging nursery (removing containers, volumes, and images)...",
361
445
  ).start();
446
+ const envFileFlag = getEnvFileFlag();
362
447
 
363
448
  await runCommandAsync(
364
- "docker-compose -f docker-compose.nursery.yml down -v --rmi all",
449
+ `docker-compose ${envFileFlag} -f docker-compose.nursery.yml down -v --rmi all`,
365
450
  {
366
451
  silent: true,
367
452
  ignoreError: true,
@@ -383,6 +468,7 @@ export async function updateNursery() {
383
468
  const spinner = ora(
384
469
  "Checking for latest Crux Garden API image from ghcr.io...",
385
470
  ).start();
471
+ const envFileFlag = getEnvFileFlag();
386
472
 
387
473
  try {
388
474
  // Get the current local image digest before pulling
@@ -394,7 +480,7 @@ export async function updateNursery() {
394
480
 
395
481
  // Pull latest images
396
482
  spinner.text = "Pulling latest images...";
397
- await runCommandAsync("docker-compose -f docker-compose.nursery.yml pull", {
483
+ await runCommandAsync(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml pull`, {
398
484
  silent: true,
399
485
  });
400
486
 
@@ -433,7 +519,7 @@ export async function updateNursery() {
433
519
  console.log();
434
520
  }
435
521
 
436
- export async function resetNursery() {
522
+ export async function resetNursery(envVars) {
437
523
  ensureDockerRunning();
438
524
  console.log(
439
525
  chalk.yellow(
@@ -450,13 +536,27 @@ export async function resetNursery() {
450
536
  return;
451
537
  }
452
538
 
539
+ // Parse and set environment variables from command line
540
+ if (envVars && envVars.length > 0) {
541
+ console.log(chalk.cyan("\nApplying environment variables:"));
542
+ parseAndSetEnvVars(envVars);
543
+ console.log();
544
+ }
545
+
453
546
  const spinner = ora("Resetting nursery environment...").start();
547
+ const envFileFlag = getEnvFileFlag();
548
+
549
+ // Get actual port values from environment
550
+ const appPort = process.env.APP_PORT || "8080";
551
+ const apiPort = process.env.API_PORT || "3000";
552
+ const postgresPort = process.env.POSTGRES_PORT || "5432";
553
+ const redisPort = process.env.REDIS_PORT || "6379";
454
554
 
455
555
  try {
456
556
  // Stop and remove volumes
457
557
  spinner.text = "Stopping and removing containers/volumes...";
458
558
  await runCommandAsync(
459
- "docker-compose -f docker-compose.nursery.yml down -v",
559
+ `docker-compose ${envFileFlag} -f docker-compose.nursery.yml down -v`,
460
560
  {
461
561
  silent: true,
462
562
  ignoreError: true,
@@ -465,14 +565,14 @@ export async function resetNursery() {
465
565
 
466
566
  // Pull latest image
467
567
  spinner.text = "Pulling latest image...";
468
- await runCommandAsync("docker-compose -f docker-compose.nursery.yml pull", {
568
+ await runCommandAsync(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml pull`, {
469
569
  silent: true,
470
570
  });
471
571
 
472
572
  // Start fresh
473
573
  spinner.text = "Starting fresh nursery environment...";
474
574
  await runCommandAsync(
475
- "docker-compose -f docker-compose.nursery.yml up -d --remove-orphans",
575
+ `docker-compose ${envFileFlag} -f docker-compose.nursery.yml up -d --remove-orphans`,
476
576
  {
477
577
  silent: true,
478
578
  },
@@ -489,16 +589,20 @@ export async function resetNursery() {
489
589
 
490
590
  spinner.succeed("Nursery environment reset complete!");
491
591
  console.log(
492
- chalk.hex(SUCCESS_GREEN)("\n✓ API running on:"),
493
- "http://localhost:3000",
592
+ chalk.hex(SUCCESS_GREEN)("\n✓ App running on:"),
593
+ `http://localhost:${appPort}`,
594
+ );
595
+ console.log(
596
+ chalk.hex(SUCCESS_GREEN)("✓ API running on:"),
597
+ `http://localhost:${apiPort}`,
494
598
  );
495
599
  console.log(
496
600
  chalk.hex(SUCCESS_GREEN)("✓ PostgreSQL running on:"),
497
- "localhost:5432",
601
+ `localhost:${postgresPort}`,
498
602
  );
499
603
  console.log(
500
604
  chalk.hex(SUCCESS_GREEN)("✓ Redis running on:"),
501
- "localhost:6379",
605
+ `localhost:${redisPort}`,
502
606
  );
503
607
  console.log(
504
608
  chalk.yellow("\nℹ Fresh nursery with latest demo data loaded"),
@@ -510,15 +614,16 @@ export async function resetNursery() {
510
614
  }
511
615
  }
512
616
 
513
- export async function restartNursery() {
617
+ export async function restartNursery(options = {}, envVars) {
514
618
  await stopNursery();
515
- await startNursery({});
619
+ await startNursery(options, envVars);
516
620
  }
517
621
 
518
622
  export async function statusNursery() {
519
623
  ensureDockerRunning();
624
+ const envFileFlag = getEnvFileFlag();
520
625
  console.log(chalk.bold("\nCrux Garden Nursery Environment Status:\n"));
521
- runCommand("docker-compose -f docker-compose.nursery.yml ps");
626
+ runCommand(`docker-compose ${envFileFlag} -f docker-compose.nursery.yml ps`);
522
627
  console.log();
523
628
  }
524
629
 
@@ -545,8 +650,9 @@ export async function connectNurseryApi() {
545
650
  export async function stopNurseryDb() {
546
651
  ensureDockerRunning();
547
652
  const spinner = ora("Stopping nursery database services...").start();
653
+ const envFileFlag = getEnvFileFlag();
548
654
  await runCommandAsync(
549
- "docker-compose -f docker-compose.nursery.yml stop postgres redis",
655
+ `docker-compose ${envFileFlag} -f docker-compose.nursery.yml stop postgres redis`,
550
656
  { silent: true },
551
657
  );
552
658
  spinner.succeed("Nursery database services stopped!");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cruxgarden/cli",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "Crux Garden CLI",
5
5
  "type": "module",
6
6
  "bin": {