@weirdfingers/baseboards 0.6.1 ā 0.7.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/dist/index.js +54 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/README.md +2 -0
- package/templates/api/.env.example +3 -0
- package/templates/api/config/generators.yaml +58 -0
- package/templates/api/pyproject.toml +1 -1
- package/templates/api/src/boards/__init__.py +1 -1
- package/templates/api/src/boards/api/endpoints/storage.py +85 -4
- package/templates/api/src/boards/api/endpoints/uploads.py +1 -2
- package/templates/api/src/boards/database/connection.py +98 -58
- package/templates/api/src/boards/generators/implementations/fal/audio/__init__.py +4 -0
- package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_text_to_speech.py +176 -0
- package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_tts_turbo.py +195 -0
- package/templates/api/src/boards/generators/implementations/fal/image/__init__.py +14 -0
- package/templates/api/src/boards/generators/implementations/fal/image/bytedance_seedream_v45_edit.py +219 -0
- package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image_edit.py +208 -0
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_15_edit.py +216 -0
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_5.py +177 -0
- package/templates/api/src/boards/generators/implementations/fal/image/reve_edit.py +178 -0
- package/templates/api/src/boards/generators/implementations/fal/image/reve_text_to_image.py +155 -0
- package/templates/api/src/boards/generators/implementations/fal/image/seedream_v45_text_to_image.py +180 -0
- package/templates/api/src/boards/generators/implementations/fal/video/__init__.py +18 -0
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_pro.py +168 -0
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_standard.py +159 -0
- package/templates/api/src/boards/generators/implementations/fal/video/veed_fabric_1_0.py +180 -0
- package/templates/api/src/boards/generators/implementations/fal/video/veo31.py +190 -0
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast.py +190 -0
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast_image_to_video.py +191 -0
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_first_last_frame_to_video.py +13 -6
- package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_image_to_video.py +212 -0
- package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_text_to_video.py +208 -0
- package/templates/api/src/boards/generators/implementations/kie/__init__.py +11 -0
- package/templates/api/src/boards/generators/implementations/kie/base.py +316 -0
- package/templates/api/src/boards/generators/implementations/kie/image/__init__.py +3 -0
- package/templates/api/src/boards/generators/implementations/kie/image/nano_banana_edit.py +190 -0
- package/templates/api/src/boards/generators/implementations/kie/utils.py +98 -0
- package/templates/api/src/boards/generators/implementations/kie/video/__init__.py +8 -0
- package/templates/api/src/boards/generators/implementations/kie/video/veo3.py +161 -0
- package/templates/api/src/boards/graphql/resolvers/upload.py +1 -1
- package/templates/web/package.json +4 -1
- package/templates/web/src/app/boards/[boardId]/page.tsx +156 -24
- package/templates/web/src/app/globals.css +3 -0
- package/templates/web/src/app/layout.tsx +15 -5
- package/templates/web/src/components/boards/ArtifactInputSlots.tsx +9 -9
- package/templates/web/src/components/boards/ArtifactPreview.tsx +34 -18
- package/templates/web/src/components/boards/GenerationGrid.tsx +101 -7
- package/templates/web/src/components/boards/GenerationInput.tsx +21 -21
- package/templates/web/src/components/boards/GeneratorSelector.tsx +232 -30
- package/templates/web/src/components/boards/UploadArtifact.tsx +385 -75
- package/templates/web/src/components/header.tsx +3 -1
- package/templates/web/src/components/theme-provider.tsx +10 -0
- package/templates/web/src/components/theme-toggle.tsx +75 -0
- package/templates/web/src/components/ui/alert-dialog.tsx +157 -0
- package/templates/web/src/components/ui/toast.tsx +128 -0
- package/templates/web/src/components/ui/toaster.tsx +35 -0
- package/templates/web/src/components/ui/use-toast.ts +186 -0
package/dist/index.js
CHANGED
|
@@ -160,6 +160,7 @@ function detectMissingProviderKeys(envPath) {
|
|
|
160
160
|
const providerKeys = [
|
|
161
161
|
"REPLICATE_API_TOKEN",
|
|
162
162
|
"FAL_KEY",
|
|
163
|
+
"KIE_API_KEY",
|
|
163
164
|
"OPENAI_API_KEY",
|
|
164
165
|
"GOOGLE_API_KEY"
|
|
165
166
|
];
|
|
@@ -303,6 +304,9 @@ async function up(directory, options) {
|
|
|
303
304
|
console.log(
|
|
304
305
|
chalk2.cyan(" \u2022 FAL_KEY") + chalk2.gray(" - https://fal.ai/dashboard/keys")
|
|
305
306
|
);
|
|
307
|
+
console.log(
|
|
308
|
+
chalk2.cyan(" \u2022 KIE_API_KEY") + chalk2.gray(" - https://kie.ai/dashboard")
|
|
309
|
+
);
|
|
306
310
|
console.log(
|
|
307
311
|
chalk2.cyan(" \u2022 OPENAI_API_KEY") + chalk2.gray(" - https://platform.openai.com/api-keys")
|
|
308
312
|
);
|
|
@@ -315,7 +319,7 @@ async function up(directory, options) {
|
|
|
315
319
|
)
|
|
316
320
|
);
|
|
317
321
|
}
|
|
318
|
-
await startDockerCompose(ctx
|
|
322
|
+
await startDockerCompose(ctx);
|
|
319
323
|
await waitForHealthy(ctx);
|
|
320
324
|
await runMigrations(ctx);
|
|
321
325
|
printSuccessMessage(ctx, !options.attach, missingKeys.length > 0);
|
|
@@ -323,7 +327,8 @@ async function up(directory, options) {
|
|
|
323
327
|
try {
|
|
324
328
|
await attachToLogs(ctx);
|
|
325
329
|
} catch (error) {
|
|
326
|
-
|
|
330
|
+
const maybeProcError = error;
|
|
331
|
+
if (maybeProcError.signal === "SIGINT" || maybeProcError.exitCode === 130) {
|
|
327
332
|
console.log(chalk2.yellow("\n\n\u26A0\uFE0F Interrupted - services stopped"));
|
|
328
333
|
process.exit(0);
|
|
329
334
|
}
|
|
@@ -424,6 +429,12 @@ async function promptForApiKeys(ctx) {
|
|
|
424
429
|
message: "Fal AI API Key (https://fal.ai/dashboard/keys):",
|
|
425
430
|
initial: ""
|
|
426
431
|
},
|
|
432
|
+
{
|
|
433
|
+
type: "password",
|
|
434
|
+
name: "KIE_API_KEY",
|
|
435
|
+
message: "Kie AI API Key (https://kie.ai/dashboard):",
|
|
436
|
+
initial: ""
|
|
437
|
+
},
|
|
427
438
|
{
|
|
428
439
|
type: "password",
|
|
429
440
|
name: "OPENAI_API_KEY",
|
|
@@ -438,6 +449,9 @@ async function promptForApiKeys(ctx) {
|
|
|
438
449
|
if (response.FAL_KEY && response.FAL_KEY.trim()) {
|
|
439
450
|
apiKeys.FAL_KEY = response.FAL_KEY.trim();
|
|
440
451
|
}
|
|
452
|
+
if (response.KIE_API_KEY && response.KIE_API_KEY.trim()) {
|
|
453
|
+
apiKeys.KIE_API_KEY = response.KIE_API_KEY.trim();
|
|
454
|
+
}
|
|
441
455
|
if (response.OPENAI_API_KEY && response.OPENAI_API_KEY.trim()) {
|
|
442
456
|
apiKeys.OPENAI_API_KEY = response.OPENAI_API_KEY.trim();
|
|
443
457
|
}
|
|
@@ -469,15 +483,25 @@ BOARDS_GENERATOR_API_KEYS=${jsonKeys}
|
|
|
469
483
|
console.log(chalk2.gray(" You can add them later by editing api/.env\n"));
|
|
470
484
|
}
|
|
471
485
|
}
|
|
472
|
-
|
|
473
|
-
const spinner = ora("Starting Docker Compose...").start();
|
|
486
|
+
function getComposeFiles(ctx) {
|
|
474
487
|
const composeFiles = ["compose.yaml"];
|
|
475
488
|
if (ctx.mode === "dev") {
|
|
476
489
|
composeFiles.push("compose.dev.yaml");
|
|
477
490
|
}
|
|
478
|
-
|
|
491
|
+
return composeFiles;
|
|
492
|
+
}
|
|
493
|
+
function getComposeBaseArgs(ctx) {
|
|
494
|
+
return [
|
|
479
495
|
"compose",
|
|
480
|
-
|
|
496
|
+
"--env-file",
|
|
497
|
+
"docker/.env",
|
|
498
|
+
...getComposeFiles(ctx).flatMap((f) => ["-f", f])
|
|
499
|
+
];
|
|
500
|
+
}
|
|
501
|
+
async function startDockerCompose(ctx) {
|
|
502
|
+
const spinner = ora("Starting Docker Compose...").start();
|
|
503
|
+
const composeArgs = [
|
|
504
|
+
...getComposeBaseArgs(ctx),
|
|
481
505
|
"up",
|
|
482
506
|
"-d",
|
|
483
507
|
"--build",
|
|
@@ -499,16 +523,7 @@ async function attachToLogs(ctx) {
|
|
|
499
523
|
chalk2.gray("\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")
|
|
500
524
|
);
|
|
501
525
|
console.log(chalk2.gray("Streaming logs... (Press Ctrl+C to stop)\n"));
|
|
502
|
-
const
|
|
503
|
-
if (ctx.mode === "dev") {
|
|
504
|
-
composeFiles.push("compose.dev.yaml");
|
|
505
|
-
}
|
|
506
|
-
const composeArgs = [
|
|
507
|
-
"compose",
|
|
508
|
-
...composeFiles.flatMap((f) => ["-f", f]),
|
|
509
|
-
"logs",
|
|
510
|
-
"-f"
|
|
511
|
-
];
|
|
526
|
+
const composeArgs = [...getComposeBaseArgs(ctx), "logs", "-f"];
|
|
512
527
|
await execa2("docker", composeArgs, {
|
|
513
528
|
cwd: ctx.dir,
|
|
514
529
|
stdio: "inherit"
|
|
@@ -522,7 +537,7 @@ async function waitForHealthy(ctx) {
|
|
|
522
537
|
try {
|
|
523
538
|
const { stdout } = await execa2(
|
|
524
539
|
"docker",
|
|
525
|
-
[
|
|
540
|
+
[...getComposeBaseArgs(ctx), "ps", "--format", "json"],
|
|
526
541
|
{
|
|
527
542
|
cwd: ctx.dir
|
|
528
543
|
}
|
|
@@ -533,7 +548,7 @@ async function waitForHealthy(ctx) {
|
|
|
533
548
|
return container && (container.Health === "healthy" || container.State === "running");
|
|
534
549
|
});
|
|
535
550
|
return allHealthy;
|
|
536
|
-
} catch
|
|
551
|
+
} catch {
|
|
537
552
|
return false;
|
|
538
553
|
}
|
|
539
554
|
};
|
|
@@ -566,7 +581,15 @@ async function runMigrations(ctx) {
|
|
|
566
581
|
try {
|
|
567
582
|
await execa2(
|
|
568
583
|
"docker",
|
|
569
|
-
[
|
|
584
|
+
[
|
|
585
|
+
...getComposeBaseArgs(ctx),
|
|
586
|
+
"exec",
|
|
587
|
+
"-T",
|
|
588
|
+
"api",
|
|
589
|
+
"alembic",
|
|
590
|
+
"upgrade",
|
|
591
|
+
"head"
|
|
592
|
+
],
|
|
570
593
|
{
|
|
571
594
|
cwd: ctx.dir
|
|
572
595
|
}
|
|
@@ -605,7 +628,9 @@ async function runMigrations(ctx) {
|
|
|
605
628
|
"\n\u26A0\uFE0F Database migrations failed. You may need to run them manually:"
|
|
606
629
|
)
|
|
607
630
|
);
|
|
608
|
-
console.log(
|
|
631
|
+
console.log(
|
|
632
|
+
chalk2.cyan(" docker compose exec api alembic upgrade head")
|
|
633
|
+
);
|
|
609
634
|
console.log(chalk2.gray("\n Error details:"));
|
|
610
635
|
console.log(chalk2.gray(" " + errorMessage));
|
|
611
636
|
}
|
|
@@ -641,7 +666,12 @@ function printSuccessMessage(ctx, detached, hasKeyWarning) {
|
|
|
641
666
|
}
|
|
642
667
|
async function checkForExistingVolumes() {
|
|
643
668
|
try {
|
|
644
|
-
const { stdout } = await execa2("docker", [
|
|
669
|
+
const { stdout } = await execa2("docker", [
|
|
670
|
+
"volume",
|
|
671
|
+
"ls",
|
|
672
|
+
"--format",
|
|
673
|
+
"{{.Name}}"
|
|
674
|
+
]);
|
|
645
675
|
const volumes = stdout.split("\n").filter(Boolean);
|
|
646
676
|
const projectVolumeName = "baseboards_db-data";
|
|
647
677
|
return volumes.includes(projectVolumeName);
|
|
@@ -653,13 +683,9 @@ async function cleanupDockerVolumes(ctx) {
|
|
|
653
683
|
const spinner = ora("Cleaning up Docker volumes...").start();
|
|
654
684
|
try {
|
|
655
685
|
if (ctx.isScaffolded) {
|
|
656
|
-
await execa2(
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
{
|
|
660
|
-
cwd: ctx.dir
|
|
661
|
-
}
|
|
662
|
-
);
|
|
686
|
+
await execa2("docker", [...getComposeBaseArgs(ctx), "down", "-v"], {
|
|
687
|
+
cwd: ctx.dir
|
|
688
|
+
});
|
|
663
689
|
} else {
|
|
664
690
|
const volumesToRemove = ["baseboards_db-data", "baseboards_api-storage"];
|
|
665
691
|
for (const volumeName of volumesToRemove) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/up.ts","../src/utils.ts","../src/commands/down.ts","../src/commands/logs.ts","../src/commands/status.ts","../src/commands/clean.ts","../src/commands/update.ts","../src/commands/doctor.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Baseboards CLI\n *\n * Main entry point for the @weirdfingers/baseboards command-line interface.\n * Provides commands to scaffold, run, and manage Baseboards installations.\n */\n\nimport { Command } from \"commander\";\nimport { readFileSync } from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join } from \"path\";\nimport chalk from \"chalk\";\n\n// Import commands\nimport { up } from \"./commands/up.js\";\nimport { down } from \"./commands/down.js\";\nimport { logs } from \"./commands/logs.js\";\nimport { status } from \"./commands/status.js\";\nimport { clean } from \"./commands/clean.js\";\nimport { update } from \"./commands/update.js\";\nimport { doctor } from \"./commands/doctor.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// Read package.json for version\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, \"../package.json\"), \"utf-8\")\n);\n\nconst program = new Command();\n\nprogram\n .name(\"baseboards\")\n .description(\n \"šØ One-command launcher for the Boards image generation platform\"\n )\n .version(packageJson.version, \"-v, --version\", \"Output the current version\");\n\n// up command\nprogram\n .command(\"up\")\n .description(\"Start Baseboards (scaffolds if needed)\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .option(\"--dev\", \"Development mode with hot reload (default)\", true)\n .option(\"--prod\", \"Production mode with prebuilt images\")\n .option(\"--attach\", \"Attach to logs (runs in foreground)\")\n .option(\"--ports <ports>\", \"Custom ports (e.g., web=3300 api=8800)\")\n .option(\"--fresh\", \"Clean up existing volumes before starting\")\n .action(up);\n\n// down command\nprogram\n .command(\"down\")\n .description(\"Stop Baseboards\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .option(\"--volumes\", \"Also remove volumes\")\n .action(down);\n\n// logs command\nprogram\n .command(\"logs\")\n .description(\"View logs from services\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .argument(\n \"[services...]\",\n \"Services to show logs for (web, api, db, cache)\",\n []\n )\n .option(\"-f, --follow\", \"Follow log output\")\n .option(\"--since <time>\", \"Show logs since timestamp (e.g., 1h, 30m)\")\n .option(\"--tail <lines>\", \"Number of lines to show from end\", \"100\")\n .action(logs);\n\n// status command\nprogram\n .command(\"status\")\n .description(\"Show status of services\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .action(status);\n\n// clean command\nprogram\n .command(\"clean\")\n .description(\"Clean up Docker resources\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .option(\"--hard\", \"Remove volumes and images (WARNING: deletes data)\")\n .action(clean);\n\n// update command\nprogram\n .command(\"update\")\n .description(\"Update Baseboards to latest version\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .option(\"--force\", \"Force update without safety checks\")\n .option(\"--version <version>\", \"Update to specific version\")\n .action(update);\n\n// doctor command\nprogram\n .command(\"doctor\")\n .description(\"Run diagnostics and show system info\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .action(doctor);\n\n// Parse without exitOverride - let commander handle exits naturally\ntry {\n await program.parseAsync(process.argv);\n} catch (error: unknown) {\n const err = error as { message?: string; stderr?: string };\n // Actual error (not help/version)\n console.error(chalk.red(\"\\nā Error:\"), err.message || \"Unknown error\");\n\n if (err.stderr) {\n console.error(chalk.gray(\"\\nDetails:\"));\n console.error(chalk.gray(err.stderr));\n }\n\n console.error(\n chalk.yellow(\"\\nš” Try running:\"),\n chalk.cyan(\"baseboards doctor\")\n );\n console.error(\n chalk.yellow(\"š Documentation:\"),\n chalk.cyan(\"https://baseboards.dev/docs\")\n );\n\n process.exit(1);\n}\n","/**\n * up command - Scaffold and start Baseboards\n */\n\nimport { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport prompts from \"prompts\";\nimport type { ProjectContext, UpOptions } from \"../types.js\";\nimport {\n assertPrerequisites,\n findAvailablePort,\n generatePassword,\n generateSecret,\n getCliVersion,\n getTemplatesDir,\n isScaffolded,\n parsePortsOption,\n detectMissingProviderKeys,\n waitFor,\n} from \"../utils.js\";\n\nexport async function up(directory: string, options: UpOptions): Promise<void> {\n console.log(chalk.blue.bold(\"\\nšØ Baseboards CLI\\n\"));\n\n // Step 1: Check prerequisites\n const spinner = ora(\"Checking prerequisites...\").start();\n await assertPrerequisites();\n spinner.succeed(\"Prerequisites OK\");\n\n // Step 2: Resolve project context\n const dir = path.resolve(process.cwd(), directory);\n const name = path.basename(dir);\n const version = getCliVersion();\n const mode = options.prod ? \"prod\" : \"dev\";\n\n // Parse custom ports\n let customPorts = {};\n if (options.ports) {\n customPorts = parsePortsOption(options.ports);\n }\n\n // Default ports\n const defaultPorts = {\n web: 3300,\n api: 8800,\n db: 5432,\n redis: 6379,\n ...customPorts,\n };\n\n const ctx: ProjectContext = {\n dir,\n name,\n isScaffolded: isScaffolded(dir),\n ports: defaultPorts,\n mode,\n version,\n };\n\n // Track if this is a fresh scaffold to prompt for API keys later\n const isFreshScaffold = !ctx.isScaffolded;\n\n // Step 3: Handle existing volumes if needed\n // If user wants fresh start OR if scaffolding fresh but volumes exist\n if (options.fresh || !ctx.isScaffolded) {\n const hasExistingVolumes = await checkForExistingVolumes();\n\n if (hasExistingVolumes) {\n if (options.fresh) {\n // --fresh flag provided, clean up without prompting\n await cleanupDockerVolumes(ctx);\n } else if (!ctx.isScaffolded) {\n // Scaffolding fresh but volumes exist - prompt user\n console.log(\n chalk.yellow(\n \"\\nā ļø Existing Docker volumes detected from a previous installation\"\n )\n );\n console.log(\n chalk.gray(\n \" To avoid password mismatch errors, you can start fresh or cancel.\"\n )\n );\n console.log(\n chalk.gray(\n \" Starting fresh will delete ALL existing data (boards, generated images, users).\"\n )\n );\n\n const response = await prompts({\n type: \"confirm\",\n name: \"cleanVolumes\",\n message: \"Delete existing volumes and start fresh?\",\n initial: true,\n });\n\n if (response.cleanVolumes === undefined) {\n // User cancelled (Ctrl+C)\n console.log(chalk.yellow(\"\\nā ļø Cancelled by user\"));\n process.exit(0);\n }\n\n if (response.cleanVolumes) {\n await cleanupDockerVolumes(ctx);\n } else {\n console.log(\n chalk.yellow(\n \"\\nā ļø Proceeding without cleaning volumes. If you encounter password errors:\"\n )\n );\n console.log(\n chalk.cyan(\" baseboards up --fresh\") +\n chalk.gray(\" (start fresh)\")\n );\n console.log(\n chalk.cyan(\" baseboards down --volumes && baseboards up\") +\n chalk.gray(\" (manual cleanup)\")\n );\n }\n }\n }\n }\n\n // Step 4: Scaffold if needed\n if (!ctx.isScaffolded) {\n console.log(\n chalk.cyan(`\\nš¦ Scaffolding new project: ${chalk.bold(name)}`)\n );\n await scaffoldProject(ctx);\n } else {\n console.log(\n chalk.green(`\\nā
Project already scaffolded: ${chalk.bold(name)}`)\n );\n }\n\n // Step 4: Check ports availability\n spinner.start(\"Checking port availability...\");\n ctx.ports.web = await findAvailablePort(ctx.ports.web);\n ctx.ports.api = await findAvailablePort(ctx.ports.api);\n spinner.succeed(\n `Ports available: web=${ctx.ports.web}, api=${ctx.ports.api}`\n );\n\n // Step 5: Ensure environment files\n await ensureEnvFiles(ctx);\n\n // Step 5.5: Prompt for API keys (only on fresh scaffold)\n if (isFreshScaffold) {\n await promptForApiKeys(ctx);\n }\n\n // Step 6: Detect missing API keys\n const apiEnvPath = path.join(ctx.dir, \"api/.env\");\n const missingKeys = detectMissingProviderKeys(apiEnvPath);\n\n if (missingKeys.length > 0) {\n console.log(chalk.yellow(\"\\nā ļø Provider API keys not configured!\"));\n console.log(chalk.gray(\" Add at least one API key to api/.env:\"));\n console.log(\n chalk.cyan(\" ⢠REPLICATE_API_TOKEN\") +\n chalk.gray(\" - https://replicate.com/account/api-tokens\")\n );\n console.log(\n chalk.cyan(\" ⢠FAL_KEY\") +\n chalk.gray(\" - https://fal.ai/dashboard/keys\")\n );\n console.log(\n chalk.cyan(\" ⢠OPENAI_API_KEY\") +\n chalk.gray(\" - https://platform.openai.com/api-keys\")\n );\n console.log(\n chalk.cyan(\" ⢠GOOGLE_API_KEY\") +\n chalk.gray(\" - https://makersuite.google.com/app/apikey\")\n );\n console.log(\n chalk.gray(\n \"\\n The app will start, but image generation won't work without keys.\\n\"\n )\n );\n }\n\n // Step 7: Start Docker Compose (always detached initially)\n await startDockerCompose(ctx, true);\n\n // Step 8: Wait for health checks\n await waitForHealthy(ctx);\n\n // Step 9: Run database migrations\n await runMigrations(ctx);\n\n // Step 10: Print success message\n printSuccessMessage(ctx, !options.attach, missingKeys.length > 0);\n\n // Step 11: Attach to logs if --attach flag is provided\n if (options.attach) {\n try {\n await attachToLogs(ctx);\n } catch (error: any) {\n // Handle Ctrl+C gracefully\n if (error.signal === \"SIGINT\" || error.exitCode === 130) {\n console.log(chalk.yellow(\"\\n\\nā ļø Interrupted - services stopped\"));\n process.exit(0);\n }\n throw error;\n }\n }\n}\n\n/**\n * Scaffold a new project from templates\n */\nasync function scaffoldProject(ctx: ProjectContext): Promise<void> {\n const templatesDir = getTemplatesDir();\n const spinner = ora(\"Copying templates...\").start();\n\n // Create project directory\n fs.ensureDirSync(ctx.dir);\n\n // Copy web and api directly to root\n fs.copySync(path.join(templatesDir, \"web\"), path.join(ctx.dir, \"web\"));\n fs.copySync(path.join(templatesDir, \"api\"), path.join(ctx.dir, \"api\"));\n\n // Copy root files (compose, docker, README, .gitignore)\n const rootFiles = [\n \"compose.yaml\",\n \"compose.dev.yaml\",\n \"README.md\",\n \".gitignore\",\n ];\n for (const file of rootFiles) {\n const src = path.join(templatesDir, file);\n const dest = path.join(ctx.dir, file);\n if (fs.existsSync(src)) {\n fs.copySync(src, dest);\n }\n }\n\n // Copy docker directory\n fs.copySync(path.join(templatesDir, \"docker\"), path.join(ctx.dir, \"docker\"));\n\n spinner.succeed(\"Templates copied\");\n\n // Create data/storage directory\n spinner.start(\"Creating data directories...\");\n fs.ensureDirSync(path.join(ctx.dir, \"data/storage\"));\n spinner.succeed(\"Data directories created\");\n\n console.log(chalk.green(\" ⨠Project scaffolded successfully!\"));\n}\n\n/**\n * Ensure .env files exist and are populated\n */\nasync function ensureEnvFiles(ctx: ProjectContext): Promise<void> {\n const spinner = ora(\"Configuring environment...\").start();\n\n // Web .env\n const webEnvPath = path.join(ctx.dir, \"web/.env\");\n const webEnvExamplePath = path.join(ctx.dir, \"web/.env.example\");\n\n if (!fs.existsSync(webEnvPath) && fs.existsSync(webEnvExamplePath)) {\n let webEnv = fs.readFileSync(webEnvExamplePath, \"utf-8\");\n webEnv = webEnv.replace(\n \"http://localhost:8800\",\n `http://localhost:${ctx.ports.api}`\n );\n fs.writeFileSync(webEnvPath, webEnv);\n }\n\n // API .env\n const apiEnvPath = path.join(ctx.dir, \"api/.env\");\n const apiEnvExamplePath = path.join(ctx.dir, \"api/.env.example\");\n\n if (!fs.existsSync(apiEnvPath) && fs.existsSync(apiEnvExamplePath)) {\n let apiEnv = fs.readFileSync(apiEnvExamplePath, \"utf-8\");\n\n // Generate JWT secret if not present\n if (\n apiEnv.includes(\"BOARDS_JWT_SECRET=\\n\") ||\n apiEnv.includes(\"BOARDS_JWT_SECRET=\\r\\n\")\n ) {\n const jwtSecret = generateSecret(32);\n apiEnv = apiEnv.replace(\n /BOARDS_JWT_SECRET=.*$/m,\n `BOARDS_JWT_SECRET=${jwtSecret}`\n );\n }\n\n fs.writeFileSync(apiEnvPath, apiEnv);\n }\n\n // Docker .env\n const dockerEnvPath = path.join(ctx.dir, \"docker/.env\");\n const dockerEnvExamplePath = path.join(ctx.dir, \"docker/env.example\");\n\n if (!fs.existsSync(dockerEnvPath) && fs.existsSync(dockerEnvExamplePath)) {\n let dockerEnv = fs.readFileSync(dockerEnvExamplePath, \"utf-8\");\n\n // Generate database password\n const dbPassword = generatePassword(24);\n // URL-encode the password for use in database URLs\n const dbPasswordEncoded = encodeURIComponent(dbPassword);\n\n dockerEnv = dockerEnv.replace(\n /POSTGRES_PASSWORD=.*/g,\n `POSTGRES_PASSWORD=${dbPassword}`\n );\n dockerEnv = dockerEnv.replace(\n /REPLACE_WITH_GENERATED_PASSWORD/g,\n dbPasswordEncoded\n );\n\n // Set ports\n dockerEnv = dockerEnv.replace(/WEB_PORT=.*/g, `WEB_PORT=${ctx.ports.web}`);\n dockerEnv = dockerEnv.replace(/API_PORT=.*/g, `API_PORT=${ctx.ports.api}`);\n\n // Set version\n dockerEnv = dockerEnv.replace(/VERSION=.*/g, `VERSION=${ctx.version}`);\n\n // Set project name\n dockerEnv = dockerEnv.replace(\n /PROJECT_NAME=.*/g,\n `PROJECT_NAME=${ctx.name}`\n );\n\n fs.writeFileSync(dockerEnvPath, dockerEnv);\n }\n\n spinner.succeed(\"Environment configured\");\n}\n\n/**\n * Prompt user for API keys during initial scaffold\n */\nasync function promptForApiKeys(ctx: ProjectContext): Promise<void> {\n console.log(chalk.cyan(\"\\nš API Key Configuration\"));\n console.log(chalk.gray(\"Add API keys to enable image generation providers\"));\n console.log(chalk.gray(\"Press Enter to skip any key\\n\"));\n\n const response = await prompts([\n {\n type: \"password\",\n name: \"REPLICATE_API_TOKEN\",\n message: \"Replicate API Key (https://replicate.com/account/api-tokens):\",\n initial: \"\",\n },\n {\n type: \"password\",\n name: \"FAL_KEY\",\n message: \"Fal AI API Key (https://fal.ai/dashboard/keys):\",\n initial: \"\",\n },\n {\n type: \"password\",\n name: \"OPENAI_API_KEY\",\n message: \"OpenAI API Key (https://platform.openai.com/api-keys):\",\n initial: \"\",\n },\n ]);\n\n // Build the API keys dictionary (only include non-empty keys)\n const apiKeys: Record<string, string> = {};\n\n if (response.REPLICATE_API_TOKEN && response.REPLICATE_API_TOKEN.trim()) {\n apiKeys.REPLICATE_API_TOKEN = response.REPLICATE_API_TOKEN.trim();\n }\n\n if (response.FAL_KEY && response.FAL_KEY.trim()) {\n apiKeys.FAL_KEY = response.FAL_KEY.trim();\n }\n\n if (response.OPENAI_API_KEY && response.OPENAI_API_KEY.trim()) {\n apiKeys.OPENAI_API_KEY = response.OPENAI_API_KEY.trim();\n }\n\n // Only write if we have at least one key\n if (Object.keys(apiKeys).length > 0) {\n // Read current api/.env\n const apiEnvPath = path.join(ctx.dir, \"api/.env\");\n let apiEnv = fs.readFileSync(apiEnvPath, \"utf-8\");\n\n // Format as JSON string for the environment variable\n const jsonKeys = JSON.stringify(apiKeys);\n\n // Update or add BOARDS_GENERATOR_API_KEYS\n if (apiEnv.includes(\"BOARDS_GENERATOR_API_KEYS=\")) {\n apiEnv = apiEnv.replace(\n /BOARDS_GENERATOR_API_KEYS=.*$/m,\n `BOARDS_GENERATOR_API_KEYS=${jsonKeys}`\n );\n } else {\n // Add it after the JWT secret section\n apiEnv = apiEnv.replace(\n /(BOARDS_JWT_SECRET=.*\\n)/,\n `$1\\n# Generator API Keys (JSON format)\\nBOARDS_GENERATOR_API_KEYS=${jsonKeys}\\n`\n );\n }\n\n fs.writeFileSync(apiEnvPath, apiEnv);\n\n console.log(chalk.green(\"\\nā
API keys saved to api/.env\"));\n console.log(\n chalk.gray(\" You can edit this file anytime to add/update keys\\n\")\n );\n } else {\n console.log(chalk.yellow(\"\\nā ļø No API keys provided\"));\n console.log(chalk.gray(\" You can add them later by editing api/.env\\n\"));\n }\n}\n\n/**\n * Start Docker Compose (always in detached mode)\n */\nasync function startDockerCompose(\n ctx: ProjectContext,\n detached: boolean\n): Promise<void> {\n const spinner = ora(\"Starting Docker Compose...\").start();\n\n const composeFiles = [\"compose.yaml\"];\n if (ctx.mode === \"dev\") {\n composeFiles.push(\"compose.dev.yaml\");\n }\n\n const composeArgs = [\n \"compose\",\n ...composeFiles.flatMap((f) => [\"-f\", f]),\n \"up\",\n \"-d\",\n \"--build\",\n \"--remove-orphans\",\n ];\n\n try {\n await execa(\"docker\", composeArgs, {\n cwd: ctx.dir,\n stdio: \"inherit\",\n });\n spinner.succeed(\"Docker Compose started\");\n } catch (error: any) {\n spinner.fail(\"Failed to start Docker Compose\");\n throw error;\n }\n}\n\n/**\n * Attach to Docker Compose logs (foreground)\n */\nasync function attachToLogs(ctx: ProjectContext): Promise<void> {\n console.log(\n chalk.gray(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\")\n );\n console.log(chalk.gray(\"Streaming logs... (Press Ctrl+C to stop)\\n\"));\n\n const composeFiles = [\"compose.yaml\"];\n if (ctx.mode === \"dev\") {\n composeFiles.push(\"compose.dev.yaml\");\n }\n\n const composeArgs = [\n \"compose\",\n ...composeFiles.flatMap((f) => [\"-f\", f]),\n \"logs\",\n \"-f\",\n ];\n\n await execa(\"docker\", composeArgs, {\n cwd: ctx.dir,\n stdio: \"inherit\",\n });\n}\n\n/**\n * Wait for services to become healthy\n */\nasync function waitForHealthy(ctx: ProjectContext): Promise<void> {\n const spinner = ora(\"Waiting for services to be healthy...\").start();\n\n const services = [\"db\", \"cache\", \"api\", \"worker\", \"web\"];\n const maxWaitMs = 120_000; // 2 minutes\n\n const checkHealth = async (): Promise<boolean> => {\n try {\n const { stdout } = await execa(\n \"docker\",\n [\"compose\", \"ps\", \"--format\", \"json\"],\n {\n cwd: ctx.dir,\n }\n );\n\n const containers = stdout\n .split(\"\\n\")\n .filter(Boolean)\n .map((line) => JSON.parse(line));\n\n const allHealthy = services.every((service) => {\n const container = containers.find((c: any) => c.Service === service);\n return (\n container &&\n (container.Health === \"healthy\" || container.State === \"running\")\n );\n });\n\n return allHealthy;\n } catch (e) {\n return false;\n }\n };\n\n const success = await waitFor(checkHealth, {\n timeoutMs: maxWaitMs,\n intervalMs: 2000,\n onProgress: (elapsed) => {\n const seconds = Math.floor(elapsed / 1000);\n spinner.text = `Waiting for services to be healthy... (${seconds}s)`;\n },\n });\n\n if (success) {\n spinner.succeed(\"All services healthy\");\n } else {\n spinner.warn(\"Services taking longer than expected...\");\n console.log(\n chalk.yellow(\n \"\\nā ļø Health check timeout. Services may still be starting.\"\n )\n );\n console.log(\n chalk.gray(\" Run\"),\n chalk.cyan(\"baseboards logs\"),\n chalk.gray(\"to check progress.\")\n );\n }\n}\n\n/**\n * Run database migrations\n */\nasync function runMigrations(ctx: ProjectContext): Promise<void> {\n const spinner = ora(\"Running database migrations...\").start();\n\n try {\n await execa(\n \"docker\",\n [\"compose\", \"exec\", \"-T\", \"api\", \"alembic\", \"upgrade\", \"head\"],\n {\n cwd: ctx.dir,\n }\n );\n spinner.succeed(\"Database migrations complete\");\n } catch (error) {\n spinner.fail(\"Database migrations failed\");\n\n // Check if this is a password authentication error\n const errorMessage = error instanceof Error ? error.message : String(error);\n const isPasswordError =\n errorMessage.includes(\"password authentication failed\") ||\n errorMessage.includes(\"InvalidPasswordError\");\n\n if (isPasswordError) {\n console.log(\n chalk.red(\n \"\\nā Database password mismatch - cannot connect to existing database\"\n )\n );\n console.log(\n chalk.yellow(\n \" Existing database volumes have a different password than the current configuration.\"\n )\n );\n console.log(chalk.yellow(\"\\n To fix this, choose one of:\"));\n console.log(\n chalk.cyan(\" 1. Start fresh (deletes data):\") +\n chalk.gray(\" baseboards down --volumes && baseboards up\")\n );\n console.log(\n chalk.cyan(\" 2. Start fresh automatically:\") +\n chalk.gray(\" baseboards up --fresh\")\n );\n console.log(\n chalk.gray(\n \"\\n This usually happens when project files were deleted but Docker volumes remain.\"\n )\n );\n } else {\n console.log(\n chalk.yellow(\n \"\\nā ļø Database migrations failed. You may need to run them manually:\"\n )\n );\n console.log(chalk.cyan(\" docker compose exec api alembic upgrade head\"));\n console.log(chalk.gray(\"\\n Error details:\"));\n console.log(chalk.gray(\" \" + errorMessage));\n }\n\n // Don't throw - app can still start\n }\n}\n\n/**\n * Print success message with URLs and next steps\n */\nfunction printSuccessMessage(\n ctx: ProjectContext,\n detached: boolean,\n hasKeyWarning: boolean\n): void {\n console.log(chalk.green.bold(\"\\n⨠Baseboards is running!\\n\"));\n console.log(\n chalk.cyan(\" š Web:\"),\n chalk.underline(`http://localhost:${ctx.ports.web}`)\n );\n console.log(\n chalk.cyan(\" š API:\"),\n chalk.underline(`http://localhost:${ctx.ports.api}`)\n );\n console.log(\n chalk.cyan(\" š GraphQL:\"),\n chalk.underline(`http://localhost:${ctx.ports.api}/graphql`)\n );\n\n if (hasKeyWarning) {\n console.log(chalk.yellow(\"\\nā ļø Remember to configure provider API keys!\"));\n console.log(chalk.gray(\" Edit:\"), chalk.cyan(\"api/.env\"));\n console.log(\n chalk.gray(\" Docs:\"),\n chalk.cyan(\"https://baseboards.dev/docs/setup\")\n );\n }\n\n console.log(chalk.gray(\"\\nš Commands:\"));\n console.log(chalk.gray(\" Stop:\"), chalk.cyan(\"baseboards down\"));\n console.log(chalk.gray(\" Logs:\"), chalk.cyan(\"baseboards logs\"));\n console.log(chalk.gray(\" Status:\"), chalk.cyan(\"baseboards status\"));\n console.log();\n}\n\n/**\n * Check if Docker volumes exist for this project\n */\nasync function checkForExistingVolumes(): Promise<boolean> {\n try {\n const { stdout } = await execa(\"docker\", [\"volume\", \"ls\", \"--format\", \"{{.Name}}\"]);\n const volumes = stdout.split(\"\\n\").filter(Boolean);\n\n // Check for the project-specific database volume\n // Volume name format: baseboards_db-data\n // NOTE: We use \"baseboards\" (not ctx.name) because the compose.yaml template\n // sets `name: ${PROJECT_NAME:-baseboards}` and the PROJECT_NAME env var is only\n // read from docker/.env for service env vars, not for the compose project name itself.\n // So all Baseboards installations use the same \"baseboards\" project name.\n const projectVolumeName = \"baseboards_db-data\";\n return volumes.includes(projectVolumeName);\n } catch {\n // If docker command fails, assume no volumes exist\n return false;\n }\n}\n\n/**\n * Clean up Docker volumes for this project\n */\nasync function cleanupDockerVolumes(ctx: ProjectContext): Promise<void> {\n const spinner = ora(\"Cleaning up Docker volumes...\").start();\n\n try {\n // If compose files exist, use docker compose down -v\n if (ctx.isScaffolded) {\n await execa(\n \"docker\",\n [\"compose\", \"down\", \"-v\"],\n {\n cwd: ctx.dir,\n }\n );\n } else {\n // If no compose files yet, manually remove the volume by name\n // This handles the case where project was deleted but volumes remain\n const volumesToRemove = [\"baseboards_db-data\", \"baseboards_api-storage\"];\n\n for (const volumeName of volumesToRemove) {\n try {\n await execa(\"docker\", [\"volume\", \"rm\", volumeName]);\n spinner.text = `Removing volume ${volumeName}...`;\n } catch {\n // Volume might not exist, that's okay - it may have been manually removed\n // or never created in the first place\n }\n }\n }\n spinner.succeed(\"Docker volumes cleaned up\");\n } catch (error) {\n spinner.fail(\"Failed to clean up volumes\");\n console.log(\n chalk.yellow(\n \"\\nā ļø Could not clean up volumes automatically. Try manually:\"\n )\n );\n console.log(chalk.cyan(\" docker volume rm baseboards_db-data\"));\n throw error;\n }\n}\n","/**\n * Utility functions for the Baseboards CLI\n */\n\nimport { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport which from \"which\";\nimport type { Prerequisites, ProjectContext } from \"./types.js\";\nimport chalk from \"chalk\";\nimport crypto from \"crypto\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/**\n * Get the templates directory (bundled with the CLI package)\n */\nexport function getTemplatesDir(): string {\n // In built package, templates are at root level next to dist/\n return path.join(__dirname, \"../templates\");\n}\n\n/**\n * Check system prerequisites\n */\nexport async function checkPrerequisites(): Promise<Prerequisites> {\n const prereqs: Prerequisites = {\n docker: { installed: false },\n node: { installed: true, satisfies: false },\n platform: { name: process.platform },\n };\n\n // Check Docker\n try {\n const dockerPath = await which(\"docker\");\n prereqs.docker.installed = !!dockerPath;\n\n if (dockerPath) {\n const { stdout } = await execa(\"docker\", [\"--version\"]);\n const match = stdout.match(/Docker version ([\\d.]+)/);\n if (match) {\n prereqs.docker.version = match[1];\n }\n\n // Check Docker Compose\n try {\n const { stdout: composeStdout } = await execa(\"docker\", [\n \"compose\",\n \"version\",\n ]);\n const composeMatch = composeStdout.match(/version v?([\\d.]+)/);\n if (composeMatch) {\n prereqs.docker.composeVersion = composeMatch[1];\n }\n } catch (e) {\n // Compose not available\n }\n }\n } catch (e) {\n // Docker not installed\n }\n\n // Check Node version\n const nodeVersion = process.version.replace(\"v\", \"\");\n prereqs.node.version = nodeVersion;\n\n const majorVersion = parseInt(nodeVersion.split(\".\")[0], 10);\n prereqs.node.satisfies = majorVersion >= 20;\n\n // Check if WSL\n if (process.platform === \"linux\") {\n try {\n const { stdout } = await execa(\"uname\", [\"-r\"]);\n if (\n stdout.toLowerCase().includes(\"microsoft\") ||\n stdout.toLowerCase().includes(\"wsl\")\n ) {\n prereqs.platform.isWSL = true;\n }\n } catch (e) {\n // Not WSL or can't determine\n }\n }\n\n return prereqs;\n}\n\n/**\n * Assert that prerequisites are met, or exit with helpful error\n */\nexport async function assertPrerequisites(): Promise<void> {\n const prereqs = await checkPrerequisites();\n\n const errors: string[] = [];\n\n if (!prereqs.docker.installed) {\n errors.push(\n \"š³ Docker is not installed.\",\n \" Install from: https://docs.docker.com/get-docker/\"\n );\n } else if (!prereqs.docker.composeVersion) {\n errors.push(\n \"š³ Docker Compose (v2) is not available.\",\n \" Update Docker to get Compose v2: https://docs.docker.com/compose/install/\"\n );\n }\n\n if (!prereqs.node.satisfies) {\n errors.push(\n `ā ļø Node.js ${prereqs.node.version} is too old (need v20+).`,\n \" Install from: https://nodejs.org/\"\n );\n }\n\n if (errors.length > 0) {\n console.error(chalk.red(\"\\nā Prerequisites not met:\\n\"));\n errors.forEach((err) => console.error(chalk.yellow(err)));\n console.error(\"\");\n process.exit(1);\n }\n}\n\n/**\n * Check if a directory is already scaffolded\n */\nexport function isScaffolded(dir: string): boolean {\n // Check for key files that indicate scaffolding\n const keyFiles = [\"compose.yaml\", \"web/package.json\", \"api/pyproject.toml\"];\n\n return keyFiles.every((file) => fs.existsSync(path.join(dir, file)));\n}\n\n/**\n * Find an available port\n */\nexport async function findAvailablePort(\n preferred: number,\n maxAttempts = 50\n): Promise<number> {\n for (let port = preferred; port < preferred + maxAttempts; port++) {\n if (await isPortAvailable(port)) {\n return port;\n }\n }\n throw new Error(`No available port found near ${preferred}`);\n}\n\n/**\n * Check if a port is available\n */\nasync function isPortAvailable(port: number): Promise<boolean> {\n const { createServer } = await import(\"net\");\n return new Promise((resolve) => {\n const server = createServer();\n server.once(\"error\", () => resolve(false));\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n server.listen(port);\n });\n}\n\n/**\n * Generate a random secure string\n */\nexport function generateSecret(length = 32): string {\n return crypto.randomBytes(length).toString(\"hex\");\n}\n\n/**\n * Generate a random password\n */\nexport function generatePassword(length = 24): string {\n const charset =\n \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#%^&*\";\n let password = \"\";\n const bytes = crypto.randomBytes(length);\n\n for (let i = 0; i < length; i++) {\n password += charset[bytes[i] % charset.length];\n }\n\n return password;\n}\n\n/**\n * Parse custom ports string (e.g., \"web=3300 api=8800\")\n */\nexport function parsePortsOption(portsStr: string): Partial<{\n web: number;\n api: number;\n db: number;\n redis: number;\n}> {\n const ports: any = {};\n const pairs = portsStr.split(/\\s+/);\n\n for (const pair of pairs) {\n const [service, port] = pair.split(\"=\");\n const portNum = parseInt(port, 10);\n if (\n service &&\n [\"web\", \"api\", \"db\", \"redis\"].includes(service) &&\n !isNaN(portNum)\n ) {\n ports[service] = portNum;\n }\n }\n\n return ports;\n}\n\n/**\n * Read package.json version\n */\nexport function getCliVersion(): string {\n const packagePath = path.join(__dirname, \"../package.json\");\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf-8\"));\n return packageJson.version;\n}\n\n/**\n * Detect missing provider API keys in .env file\n */\nexport function detectMissingProviderKeys(envPath: string): string[] {\n if (!fs.existsSync(envPath)) {\n return [];\n }\n\n const envContent = fs.readFileSync(envPath, \"utf-8\");\n const providerKeys = [\n \"REPLICATE_API_TOKEN\",\n \"FAL_KEY\",\n \"OPENAI_API_KEY\",\n \"GOOGLE_API_KEY\",\n ];\n\n const missingKeys: string[] = [];\n\n for (const key of providerKeys) {\n const regex = new RegExp(`^${key}=(.*)$`, \"m\");\n const match = envContent.match(regex);\n\n // Key is missing if not found or if value is empty\n if (!match || !match[1] || match[1].trim() === \"\") {\n missingKeys.push(key);\n }\n }\n\n // If all keys are missing, user hasn't configured any\n if (missingKeys.length === providerKeys.length) {\n return missingKeys;\n }\n\n return [];\n}\n\n/**\n * Wait for a condition with timeout\n */\nexport async function waitFor(\n condition: () => Promise<boolean>,\n options: {\n timeoutMs: number;\n intervalMs?: number;\n onProgress?: (elapsed: number) => void;\n }\n): Promise<boolean> {\n const { timeoutMs, intervalMs = 1000, onProgress } = options;\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n if (await condition()) {\n return true;\n }\n\n if (onProgress) {\n onProgress(Date.now() - startTime);\n }\n\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n\n return false;\n}\n","/**\n * down command - Stop Baseboards\n */\n\nimport { execa } from 'execa';\nimport path from 'path';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport type { DownOptions } from '../types.js';\nimport { isScaffolded } from '../utils.js';\n\nexport async function down(directory: string, options: DownOptions): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n const spinner = ora('Stopping services...').start();\n\n const args = ['compose', 'down'];\n if (options.volumes) {\n args.push('--volumes');\n }\n\n try {\n await execa('docker', args, {\n cwd: dir,\n });\n\n spinner.succeed('Services stopped');\n\n if (options.volumes) {\n console.log(chalk.yellow('ā ļø Volumes removed (database data deleted)'));\n }\n } catch (error: any) {\n spinner.fail('Failed to stop services');\n throw error;\n }\n}\n","/**\n * logs command - View service logs\n */\n\nimport { execa } from 'execa';\nimport path from 'path';\nimport chalk from 'chalk';\nimport type { LogsOptions } from '../types.js';\nimport { isScaffolded } from '../utils.js';\n\nexport async function logs(\n directory: string,\n services: string[],\n options: LogsOptions\n): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n const args = ['compose', 'logs'];\n\n if (options.follow) {\n args.push('--follow');\n }\n\n if (options.since) {\n args.push('--since', options.since);\n }\n\n if (options.tail) {\n args.push('--tail', options.tail);\n }\n\n // Add specific services if provided\n if (services.length > 0) {\n args.push(...services);\n }\n\n try {\n await execa('docker', args, {\n cwd: dir,\n stdio: 'inherit',\n });\n } catch (error: any) {\n // Ctrl+C is expected, don't treat as error\n if (error.signal !== 'SIGINT') {\n throw error;\n }\n }\n}\n","/**\n * status command - Show service status\n */\n\nimport { execa } from 'execa';\nimport path from 'path';\nimport chalk from 'chalk';\nimport { isScaffolded } from '../utils.js';\n\nexport async function status(directory: string): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n console.log(chalk.blue.bold('\\nš Service Status\\n'));\n\n try {\n await execa('docker', ['compose', 'ps'], {\n cwd: dir,\n stdio: 'inherit',\n });\n } catch (error: any) {\n console.error(chalk.red('\\nā Failed to get status'));\n throw error;\n }\n}\n","/**\n * clean command - Clean up Docker resources\n */\n\nimport { execa } from 'execa';\nimport path from 'path';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport prompts from 'prompts';\nimport type { CleanOptions } from '../types.js';\nimport { isScaffolded } from '../utils.js';\n\nexport async function clean(\n directory: string,\n options: CleanOptions\n): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n if (options.hard) {\n console.log(chalk.yellow('\\nā ļø WARNING: This will delete:'));\n console.log(chalk.yellow(' ⢠All containers'));\n console.log(chalk.yellow(' ⢠All volumes (database data will be lost)'));\n console.log(chalk.yellow(' ⢠All images'));\n\n const response = await prompts({\n type: 'confirm',\n name: 'confirmed',\n message: 'Are you sure?',\n initial: false,\n });\n\n if (!response.confirmed) {\n console.log(chalk.gray('\\nCancelled'));\n return;\n }\n }\n\n const spinner = ora('Cleaning up...').start();\n\n try {\n // Stop containers\n await execa('docker', ['compose', 'down', '--volumes', '--remove-orphans'], {\n cwd: dir,\n });\n\n if (options.hard) {\n // Remove images\n try {\n const { stdout } = await execa('docker', ['compose', 'images', '-q'], {\n cwd: dir,\n });\n\n const imageIds = stdout.split('\\n').filter(Boolean);\n if (imageIds.length > 0) {\n await execa('docker', ['rmi', ...imageIds]);\n }\n } catch (e) {\n // Images might not exist or already removed\n }\n }\n\n spinner.succeed('Cleanup complete');\n\n if (options.hard) {\n console.log(chalk.green('\\n⨠All Docker resources removed'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to start fresh.'));\n } else {\n console.log(chalk.green('\\n⨠Containers and volumes removed'));\n }\n } catch (error: any) {\n spinner.fail('Cleanup failed');\n throw error;\n }\n}\n","/**\n * update command - Update Baseboards to latest version\n */\n\nimport path from 'path';\nimport chalk from 'chalk';\nimport type { UpdateOptions } from '../types.js';\nimport { isScaffolded } from '../utils.js';\n\nexport async function update(\n directory: string,\n options: UpdateOptions\n): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n console.log(chalk.blue.bold('\\nš Update Command\\n'));\n console.log(chalk.yellow('ā ļø This feature is coming soon!'));\n console.log(chalk.gray('\\nFor now, to update:'));\n console.log(chalk.gray('1. Update the CLI:'), chalk.cyan('npm install -g @weirdfingers/baseboards@latest'));\n console.log(chalk.gray('2. Pull new images:'), chalk.cyan('docker compose pull'));\n console.log(chalk.gray('3. Restart:'), chalk.cyan('baseboards down && baseboards up'));\n console.log();\n\n // TODO: Implement update logic:\n // 1. Check for new version on npm\n // 2. Scan for modified source files (git diff or timestamp check)\n // 3. If no modifications:\n // - Copy new templates (preserving config)\n // - Pull new Docker images\n // - Update package.json versions\n // 4. If modifications detected:\n // - Warn user\n // - Offer git-based merge if repo detected\n // - Create backup otherwise\n // 5. Preserve:\n // - All .env files\n // - config/*.yaml files\n // - data/storage/ directory\n}\n","/**\n * doctor command - Run diagnostics\n */\n\nimport path from 'path';\nimport fs from 'fs-extra';\nimport chalk from 'chalk';\nimport { checkPrerequisites, isScaffolded, detectMissingProviderKeys, getCliVersion } from '../utils.js';\n\nexport async function doctor(directory: string): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n console.log(chalk.blue.bold('\\n𩺠Baseboards Diagnostics\\n'));\n\n // CLI Version\n console.log(chalk.cyan('CLI Version:'), getCliVersion());\n\n // Prerequisites\n console.log(chalk.cyan('\\nš Prerequisites:'));\n const prereqs = await checkPrerequisites();\n\n console.log(\n chalk.gray(' Node.js:'),\n prereqs.node.installed\n ? prereqs.node.satisfies\n ? chalk.green(`ā v${prereqs.node.version}`)\n : chalk.yellow(`ā ļø v${prereqs.node.version} (need v20+)`)\n : chalk.red('ā Not installed')\n );\n\n console.log(\n chalk.gray(' Docker:'),\n prereqs.docker.installed\n ? chalk.green(`ā v${prereqs.docker.version}`)\n : chalk.red('ā Not installed')\n );\n\n if (prereqs.docker.composeVersion) {\n console.log(\n chalk.gray(' Docker Compose:'),\n chalk.green(`ā v${prereqs.docker.composeVersion}`)\n );\n } else if (prereqs.docker.installed) {\n console.log(chalk.gray(' Docker Compose:'), chalk.red('ā Not available'));\n }\n\n console.log(chalk.gray(' Platform:'), prereqs.platform.name);\n if (prereqs.platform.isWSL) {\n console.log(chalk.gray(' WSL:'), chalk.blue('ā Detected'));\n }\n\n // Project info\n console.log(chalk.cyan('\\nš Project:'));\n const scaffolded = isScaffolded(dir);\n console.log(\n chalk.gray(' Scaffolded:'),\n scaffolded ? chalk.green('ā Yes') : chalk.yellow('ā No')\n );\n\n if (scaffolded) {\n console.log(chalk.gray(' Directory:'), dir);\n\n // Check for key files\n const webPkg = path.join(dir, 'web/package.json');\n const apiPkg = path.join(dir, 'api/pyproject.toml');\n const composeFile = path.join(dir, 'compose.yaml');\n\n console.log(\n chalk.gray(' Web package:'),\n fs.existsSync(webPkg) ? chalk.green('ā') : chalk.red('ā')\n );\n console.log(\n chalk.gray(' API package:'),\n fs.existsSync(apiPkg) ? chalk.green('ā') : chalk.red('ā')\n );\n console.log(\n chalk.gray(' Compose file:'),\n fs.existsSync(composeFile) ? chalk.green('ā') : chalk.red('ā')\n );\n\n // Check .env files\n console.log(chalk.cyan('\\nš Environment:'));\n const webEnv = path.join(dir, 'web/.env');\n const apiEnv = path.join(dir, 'api/.env');\n const dockerEnv = path.join(dir, 'docker/.env');\n\n console.log(\n chalk.gray(' Web .env:'),\n fs.existsSync(webEnv) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n console.log(\n chalk.gray(' API .env:'),\n fs.existsSync(apiEnv) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n console.log(\n chalk.gray(' Docker .env:'),\n fs.existsSync(dockerEnv) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n\n // Check provider keys\n if (fs.existsSync(apiEnv)) {\n const missingKeys = detectMissingProviderKeys(apiEnv);\n if (missingKeys.length > 0) {\n console.log(\n chalk.gray(' Provider keys:'),\n chalk.yellow(`ā ļø ${missingKeys.length} missing`)\n );\n console.log(chalk.gray(' Missing:'), missingKeys.map(k => chalk.cyan(k)).join(', '));\n } else {\n console.log(chalk.gray(' Provider keys:'), chalk.green('ā Configured'));\n }\n }\n\n // Check config files\n console.log(chalk.cyan('\\nāļø Configuration:'));\n const generatorsYaml = path.join(dir, 'api/config/generators.yaml');\n const storageYaml = path.join(dir, 'api/config/storage_config.yaml');\n\n console.log(\n chalk.gray(' generators.yaml:'),\n fs.existsSync(generatorsYaml) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n console.log(\n chalk.gray(' storage_config.yaml:'),\n fs.existsSync(storageYaml) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n\n // Check storage directory\n const storageDir = path.join(dir, 'data/storage');\n console.log(\n chalk.gray(' Storage directory:'),\n fs.existsSync(storageDir) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n }\n\n // Recommendations\n console.log(chalk.cyan('\\nš” Recommendations:'));\n const recommendations: string[] = [];\n\n if (!prereqs.node.satisfies) {\n recommendations.push('Upgrade Node.js to v20 or higher');\n }\n\n if (!prereqs.docker.installed) {\n recommendations.push('Install Docker Desktop: https://docs.docker.com/get-docker/');\n } else if (!prereqs.docker.composeVersion) {\n recommendations.push('Update Docker to get Compose v2');\n }\n\n if (!scaffolded) {\n recommendations.push('Run ' + chalk.cyan('baseboards up') + ' to scaffold a project');\n }\n\n if (recommendations.length === 0) {\n console.log(chalk.green(' ā Everything looks good!'));\n } else {\n recommendations.forEach((rec) => console.log(chalk.yellow(' ā¢'), rec));\n }\n\n console.log();\n}\n"],"mappings":"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","names":["fileURLToPath","chalk","execa","fs","path","chalk","packageJson","chalk","path","fs","execa","execa","path","chalk","ora","path","chalk","ora","execa","execa","path","chalk","path","chalk","execa","execa","path","chalk","path","chalk","execa","execa","path","chalk","ora","prompts","path","chalk","prompts","ora","execa","path","chalk","path","chalk","path","fs","chalk","path","chalk","fs","__filename","fileURLToPath","__dirname","chalk"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/up.ts","../src/utils.ts","../src/commands/down.ts","../src/commands/logs.ts","../src/commands/status.ts","../src/commands/clean.ts","../src/commands/update.ts","../src/commands/doctor.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Baseboards CLI\n *\n * Main entry point for the @weirdfingers/baseboards command-line interface.\n * Provides commands to scaffold, run, and manage Baseboards installations.\n */\n\nimport { Command } from \"commander\";\nimport { readFileSync } from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join } from \"path\";\nimport chalk from \"chalk\";\n\n// Import commands\nimport { up } from \"./commands/up.js\";\nimport { down } from \"./commands/down.js\";\nimport { logs } from \"./commands/logs.js\";\nimport { status } from \"./commands/status.js\";\nimport { clean } from \"./commands/clean.js\";\nimport { update } from \"./commands/update.js\";\nimport { doctor } from \"./commands/doctor.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// Read package.json for version\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, \"../package.json\"), \"utf-8\")\n);\n\nconst program = new Command();\n\nprogram\n .name(\"baseboards\")\n .description(\n \"šØ One-command launcher for the Boards image generation platform\"\n )\n .version(packageJson.version, \"-v, --version\", \"Output the current version\");\n\n// up command\nprogram\n .command(\"up\")\n .description(\"Start Baseboards (scaffolds if needed)\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .option(\"--dev\", \"Development mode with hot reload (default)\", true)\n .option(\"--prod\", \"Production mode with prebuilt images\")\n .option(\"--attach\", \"Attach to logs (runs in foreground)\")\n .option(\"--ports <ports>\", \"Custom ports (e.g., web=3300 api=8800)\")\n .option(\"--fresh\", \"Clean up existing volumes before starting\")\n .action(up);\n\n// down command\nprogram\n .command(\"down\")\n .description(\"Stop Baseboards\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .option(\"--volumes\", \"Also remove volumes\")\n .action(down);\n\n// logs command\nprogram\n .command(\"logs\")\n .description(\"View logs from services\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .argument(\n \"[services...]\",\n \"Services to show logs for (web, api, db, cache)\",\n []\n )\n .option(\"-f, --follow\", \"Follow log output\")\n .option(\"--since <time>\", \"Show logs since timestamp (e.g., 1h, 30m)\")\n .option(\"--tail <lines>\", \"Number of lines to show from end\", \"100\")\n .action(logs);\n\n// status command\nprogram\n .command(\"status\")\n .description(\"Show status of services\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .action(status);\n\n// clean command\nprogram\n .command(\"clean\")\n .description(\"Clean up Docker resources\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .option(\"--hard\", \"Remove volumes and images (WARNING: deletes data)\")\n .action(clean);\n\n// update command\nprogram\n .command(\"update\")\n .description(\"Update Baseboards to latest version\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .option(\"--force\", \"Force update without safety checks\")\n .option(\"--version <version>\", \"Update to specific version\")\n .action(update);\n\n// doctor command\nprogram\n .command(\"doctor\")\n .description(\"Run diagnostics and show system info\")\n .argument(\"[directory]\", \"Project directory\", \".\")\n .action(doctor);\n\n// Parse without exitOverride - let commander handle exits naturally\ntry {\n await program.parseAsync(process.argv);\n} catch (error: unknown) {\n const err = error as { message?: string; stderr?: string };\n // Actual error (not help/version)\n console.error(chalk.red(\"\\nā Error:\"), err.message || \"Unknown error\");\n\n if (err.stderr) {\n console.error(chalk.gray(\"\\nDetails:\"));\n console.error(chalk.gray(err.stderr));\n }\n\n console.error(\n chalk.yellow(\"\\nš” Try running:\"),\n chalk.cyan(\"baseboards doctor\")\n );\n console.error(\n chalk.yellow(\"š Documentation:\"),\n chalk.cyan(\"https://baseboards.dev/docs\")\n );\n\n process.exit(1);\n}\n","/**\n * up command - Scaffold and start Baseboards\n */\n\nimport { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport prompts from \"prompts\";\nimport type { ProjectContext, UpOptions } from \"../types.js\";\nimport {\n assertPrerequisites,\n findAvailablePort,\n generatePassword,\n generateSecret,\n getCliVersion,\n getTemplatesDir,\n isScaffolded,\n parsePortsOption,\n detectMissingProviderKeys,\n waitFor,\n} from \"../utils.js\";\n\nexport async function up(directory: string, options: UpOptions): Promise<void> {\n console.log(chalk.blue.bold(\"\\nšØ Baseboards CLI\\n\"));\n\n // Step 1: Check prerequisites\n const spinner = ora(\"Checking prerequisites...\").start();\n await assertPrerequisites();\n spinner.succeed(\"Prerequisites OK\");\n\n // Step 2: Resolve project context\n const dir = path.resolve(process.cwd(), directory);\n const name = path.basename(dir);\n const version = getCliVersion();\n const mode = options.prod ? \"prod\" : \"dev\";\n\n // Parse custom ports\n let customPorts = {};\n if (options.ports) {\n customPorts = parsePortsOption(options.ports);\n }\n\n // Default ports\n const defaultPorts = {\n web: 3300,\n api: 8800,\n db: 5432,\n redis: 6379,\n ...customPorts,\n };\n\n const ctx: ProjectContext = {\n dir,\n name,\n isScaffolded: isScaffolded(dir),\n ports: defaultPorts,\n mode,\n version,\n };\n\n // Track if this is a fresh scaffold to prompt for API keys later\n const isFreshScaffold = !ctx.isScaffolded;\n\n // Step 3: Handle existing volumes if needed\n // If user wants fresh start OR if scaffolding fresh but volumes exist\n if (options.fresh || !ctx.isScaffolded) {\n const hasExistingVolumes = await checkForExistingVolumes();\n\n if (hasExistingVolumes) {\n if (options.fresh) {\n // --fresh flag provided, clean up without prompting\n await cleanupDockerVolumes(ctx);\n } else if (!ctx.isScaffolded) {\n // Scaffolding fresh but volumes exist - prompt user\n console.log(\n chalk.yellow(\n \"\\nā ļø Existing Docker volumes detected from a previous installation\"\n )\n );\n console.log(\n chalk.gray(\n \" To avoid password mismatch errors, you can start fresh or cancel.\"\n )\n );\n console.log(\n chalk.gray(\n \" Starting fresh will delete ALL existing data (boards, generated images, users).\"\n )\n );\n\n const response = await prompts({\n type: \"confirm\",\n name: \"cleanVolumes\",\n message: \"Delete existing volumes and start fresh?\",\n initial: true,\n });\n\n if (response.cleanVolumes === undefined) {\n // User cancelled (Ctrl+C)\n console.log(chalk.yellow(\"\\nā ļø Cancelled by user\"));\n process.exit(0);\n }\n\n if (response.cleanVolumes) {\n await cleanupDockerVolumes(ctx);\n } else {\n console.log(\n chalk.yellow(\n \"\\nā ļø Proceeding without cleaning volumes. If you encounter password errors:\"\n )\n );\n console.log(\n chalk.cyan(\" baseboards up --fresh\") +\n chalk.gray(\" (start fresh)\")\n );\n console.log(\n chalk.cyan(\" baseboards down --volumes && baseboards up\") +\n chalk.gray(\" (manual cleanup)\")\n );\n }\n }\n }\n }\n\n // Step 4: Scaffold if needed\n if (!ctx.isScaffolded) {\n console.log(\n chalk.cyan(`\\nš¦ Scaffolding new project: ${chalk.bold(name)}`)\n );\n await scaffoldProject(ctx);\n } else {\n console.log(\n chalk.green(`\\nā
Project already scaffolded: ${chalk.bold(name)}`)\n );\n }\n\n // Step 4: Check ports availability\n spinner.start(\"Checking port availability...\");\n ctx.ports.web = await findAvailablePort(ctx.ports.web);\n ctx.ports.api = await findAvailablePort(ctx.ports.api);\n spinner.succeed(\n `Ports available: web=${ctx.ports.web}, api=${ctx.ports.api}`\n );\n\n // Step 5: Ensure environment files\n await ensureEnvFiles(ctx);\n\n // Step 5.5: Prompt for API keys (only on fresh scaffold)\n if (isFreshScaffold) {\n await promptForApiKeys(ctx);\n }\n\n // Step 6: Detect missing API keys\n const apiEnvPath = path.join(ctx.dir, \"api/.env\");\n const missingKeys = detectMissingProviderKeys(apiEnvPath);\n\n if (missingKeys.length > 0) {\n console.log(chalk.yellow(\"\\nā ļø Provider API keys not configured!\"));\n console.log(chalk.gray(\" Add at least one API key to api/.env:\"));\n console.log(\n chalk.cyan(\" ⢠REPLICATE_API_TOKEN\") +\n chalk.gray(\" - https://replicate.com/account/api-tokens\")\n );\n console.log(\n chalk.cyan(\" ⢠FAL_KEY\") +\n chalk.gray(\" - https://fal.ai/dashboard/keys\")\n );\n console.log(\n chalk.cyan(\" ⢠KIE_API_KEY\") + chalk.gray(\" - https://kie.ai/dashboard\")\n );\n console.log(\n chalk.cyan(\" ⢠OPENAI_API_KEY\") +\n chalk.gray(\" - https://platform.openai.com/api-keys\")\n );\n console.log(\n chalk.cyan(\" ⢠GOOGLE_API_KEY\") +\n chalk.gray(\" - https://makersuite.google.com/app/apikey\")\n );\n console.log(\n chalk.gray(\n \"\\n The app will start, but image generation won't work without keys.\\n\"\n )\n );\n }\n\n // Step 7: Start Docker Compose (always detached initially)\n await startDockerCompose(ctx);\n\n // Step 8: Wait for health checks\n await waitForHealthy(ctx);\n\n // Step 9: Run database migrations\n await runMigrations(ctx);\n\n // Step 10: Print success message\n printSuccessMessage(ctx, !options.attach, missingKeys.length > 0);\n\n // Step 11: Attach to logs if --attach flag is provided\n if (options.attach) {\n try {\n await attachToLogs(ctx);\n } catch (error: unknown) {\n // Handle Ctrl+C gracefully\n const maybeProcError = error as { signal?: string; exitCode?: number };\n if (\n maybeProcError.signal === \"SIGINT\" ||\n maybeProcError.exitCode === 130\n ) {\n console.log(chalk.yellow(\"\\n\\nā ļø Interrupted - services stopped\"));\n process.exit(0);\n }\n throw error;\n }\n }\n}\n\n/**\n * Scaffold a new project from templates\n */\nasync function scaffoldProject(ctx: ProjectContext): Promise<void> {\n const templatesDir = getTemplatesDir();\n const spinner = ora(\"Copying templates...\").start();\n\n // Create project directory\n fs.ensureDirSync(ctx.dir);\n\n // Copy web and api directly to root\n fs.copySync(path.join(templatesDir, \"web\"), path.join(ctx.dir, \"web\"));\n fs.copySync(path.join(templatesDir, \"api\"), path.join(ctx.dir, \"api\"));\n\n // Copy root files (compose, docker, README, .gitignore)\n const rootFiles = [\n \"compose.yaml\",\n \"compose.dev.yaml\",\n \"README.md\",\n \".gitignore\",\n ];\n for (const file of rootFiles) {\n const src = path.join(templatesDir, file);\n const dest = path.join(ctx.dir, file);\n if (fs.existsSync(src)) {\n fs.copySync(src, dest);\n }\n }\n\n // Copy docker directory\n fs.copySync(path.join(templatesDir, \"docker\"), path.join(ctx.dir, \"docker\"));\n\n spinner.succeed(\"Templates copied\");\n\n // Create data/storage directory\n spinner.start(\"Creating data directories...\");\n fs.ensureDirSync(path.join(ctx.dir, \"data/storage\"));\n spinner.succeed(\"Data directories created\");\n\n console.log(chalk.green(\" ⨠Project scaffolded successfully!\"));\n}\n\n/**\n * Ensure .env files exist and are populated\n */\nasync function ensureEnvFiles(ctx: ProjectContext): Promise<void> {\n const spinner = ora(\"Configuring environment...\").start();\n\n // Web .env\n const webEnvPath = path.join(ctx.dir, \"web/.env\");\n const webEnvExamplePath = path.join(ctx.dir, \"web/.env.example\");\n\n if (!fs.existsSync(webEnvPath) && fs.existsSync(webEnvExamplePath)) {\n let webEnv = fs.readFileSync(webEnvExamplePath, \"utf-8\");\n webEnv = webEnv.replace(\n \"http://localhost:8800\",\n `http://localhost:${ctx.ports.api}`\n );\n fs.writeFileSync(webEnvPath, webEnv);\n }\n\n // API .env\n const apiEnvPath = path.join(ctx.dir, \"api/.env\");\n const apiEnvExamplePath = path.join(ctx.dir, \"api/.env.example\");\n\n if (!fs.existsSync(apiEnvPath) && fs.existsSync(apiEnvExamplePath)) {\n let apiEnv = fs.readFileSync(apiEnvExamplePath, \"utf-8\");\n\n // Generate JWT secret if not present\n if (\n apiEnv.includes(\"BOARDS_JWT_SECRET=\\n\") ||\n apiEnv.includes(\"BOARDS_JWT_SECRET=\\r\\n\")\n ) {\n const jwtSecret = generateSecret(32);\n apiEnv = apiEnv.replace(\n /BOARDS_JWT_SECRET=.*$/m,\n `BOARDS_JWT_SECRET=${jwtSecret}`\n );\n }\n\n fs.writeFileSync(apiEnvPath, apiEnv);\n }\n\n // Docker .env\n const dockerEnvPath = path.join(ctx.dir, \"docker/.env\");\n const dockerEnvExamplePath = path.join(ctx.dir, \"docker/env.example\");\n\n if (!fs.existsSync(dockerEnvPath) && fs.existsSync(dockerEnvExamplePath)) {\n let dockerEnv = fs.readFileSync(dockerEnvExamplePath, \"utf-8\");\n\n // Generate database password\n const dbPassword = generatePassword(24);\n // URL-encode the password for use in database URLs\n const dbPasswordEncoded = encodeURIComponent(dbPassword);\n\n dockerEnv = dockerEnv.replace(\n /POSTGRES_PASSWORD=.*/g,\n `POSTGRES_PASSWORD=${dbPassword}`\n );\n dockerEnv = dockerEnv.replace(\n /REPLACE_WITH_GENERATED_PASSWORD/g,\n dbPasswordEncoded\n );\n\n // Set ports\n dockerEnv = dockerEnv.replace(/WEB_PORT=.*/g, `WEB_PORT=${ctx.ports.web}`);\n dockerEnv = dockerEnv.replace(/API_PORT=.*/g, `API_PORT=${ctx.ports.api}`);\n\n // Set version\n dockerEnv = dockerEnv.replace(/VERSION=.*/g, `VERSION=${ctx.version}`);\n\n // Set project name\n dockerEnv = dockerEnv.replace(\n /PROJECT_NAME=.*/g,\n `PROJECT_NAME=${ctx.name}`\n );\n\n fs.writeFileSync(dockerEnvPath, dockerEnv);\n }\n\n spinner.succeed(\"Environment configured\");\n}\n\n/**\n * Prompt user for API keys during initial scaffold\n */\nasync function promptForApiKeys(ctx: ProjectContext): Promise<void> {\n console.log(chalk.cyan(\"\\nš API Key Configuration\"));\n console.log(chalk.gray(\"Add API keys to enable image generation providers\"));\n console.log(chalk.gray(\"Press Enter to skip any key\\n\"));\n\n const response = await prompts([\n {\n type: \"password\",\n name: \"REPLICATE_API_TOKEN\",\n message: \"Replicate API Key (https://replicate.com/account/api-tokens):\",\n initial: \"\",\n },\n {\n type: \"password\",\n name: \"FAL_KEY\",\n message: \"Fal AI API Key (https://fal.ai/dashboard/keys):\",\n initial: \"\",\n },\n {\n type: \"password\",\n name: \"KIE_API_KEY\",\n message: \"Kie AI API Key (https://kie.ai/dashboard):\",\n initial: \"\",\n },\n {\n type: \"password\",\n name: \"OPENAI_API_KEY\",\n message: \"OpenAI API Key (https://platform.openai.com/api-keys):\",\n initial: \"\",\n },\n ]);\n\n // Build the API keys dictionary (only include non-empty keys)\n const apiKeys: Record<string, string> = {};\n\n if (response.REPLICATE_API_TOKEN && response.REPLICATE_API_TOKEN.trim()) {\n apiKeys.REPLICATE_API_TOKEN = response.REPLICATE_API_TOKEN.trim();\n }\n\n if (response.FAL_KEY && response.FAL_KEY.trim()) {\n apiKeys.FAL_KEY = response.FAL_KEY.trim();\n }\n\n if (response.KIE_API_KEY && response.KIE_API_KEY.trim()) {\n apiKeys.KIE_API_KEY = response.KIE_API_KEY.trim();\n }\n\n if (response.OPENAI_API_KEY && response.OPENAI_API_KEY.trim()) {\n apiKeys.OPENAI_API_KEY = response.OPENAI_API_KEY.trim();\n }\n\n // Only write if we have at least one key\n if (Object.keys(apiKeys).length > 0) {\n // Read current api/.env\n const apiEnvPath = path.join(ctx.dir, \"api/.env\");\n let apiEnv = fs.readFileSync(apiEnvPath, \"utf-8\");\n\n // Format as JSON string for the environment variable\n const jsonKeys = JSON.stringify(apiKeys);\n\n // Update or add BOARDS_GENERATOR_API_KEYS\n if (apiEnv.includes(\"BOARDS_GENERATOR_API_KEYS=\")) {\n apiEnv = apiEnv.replace(\n /BOARDS_GENERATOR_API_KEYS=.*$/m,\n `BOARDS_GENERATOR_API_KEYS=${jsonKeys}`\n );\n } else {\n // Add it after the JWT secret section\n apiEnv = apiEnv.replace(\n /(BOARDS_JWT_SECRET=.*\\n)/,\n `$1\\n# Generator API Keys (JSON format)\\nBOARDS_GENERATOR_API_KEYS=${jsonKeys}\\n`\n );\n }\n\n fs.writeFileSync(apiEnvPath, apiEnv);\n\n console.log(chalk.green(\"\\nā
API keys saved to api/.env\"));\n console.log(\n chalk.gray(\" You can edit this file anytime to add/update keys\\n\")\n );\n } else {\n console.log(chalk.yellow(\"\\nā ļø No API keys provided\"));\n console.log(chalk.gray(\" You can add them later by editing api/.env\\n\"));\n }\n}\n\nfunction getComposeFiles(ctx: ProjectContext): string[] {\n const composeFiles = [\"compose.yaml\"];\n if (ctx.mode === \"dev\") {\n composeFiles.push(\"compose.dev.yaml\");\n }\n return composeFiles;\n}\n\nfunction getComposeBaseArgs(ctx: ProjectContext): string[] {\n // IMPORTANT: use docker/.env for compose interpolation (e.g. PROJECT_NAME, ports)\n // and keep it in sync with env_file usage inside compose.yaml.\n return [\n \"compose\",\n \"--env-file\",\n \"docker/.env\",\n ...getComposeFiles(ctx).flatMap((f) => [\"-f\", f]),\n ];\n}\n\n/**\n * Start Docker Compose (always in detached mode)\n */\nasync function startDockerCompose(ctx: ProjectContext): Promise<void> {\n const spinner = ora(\"Starting Docker Compose...\").start();\n\n const composeArgs = [\n ...getComposeBaseArgs(ctx),\n \"up\",\n \"-d\",\n \"--build\",\n \"--remove-orphans\",\n ];\n\n try {\n await execa(\"docker\", composeArgs, {\n cwd: ctx.dir,\n stdio: \"inherit\",\n });\n spinner.succeed(\"Docker Compose started\");\n } catch (error: unknown) {\n spinner.fail(\"Failed to start Docker Compose\");\n throw error;\n }\n}\n\n/**\n * Attach to Docker Compose logs (foreground)\n */\nasync function attachToLogs(ctx: ProjectContext): Promise<void> {\n console.log(\n chalk.gray(\"\\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\")\n );\n console.log(chalk.gray(\"Streaming logs... (Press Ctrl+C to stop)\\n\"));\n\n const composeArgs = [...getComposeBaseArgs(ctx), \"logs\", \"-f\"];\n\n await execa(\"docker\", composeArgs, {\n cwd: ctx.dir,\n stdio: \"inherit\",\n });\n}\n\n/**\n * Wait for services to become healthy\n */\nasync function waitForHealthy(ctx: ProjectContext): Promise<void> {\n const spinner = ora(\"Waiting for services to be healthy...\").start();\n\n const services = [\"db\", \"cache\", \"api\", \"worker\", \"web\"];\n const maxWaitMs = 120_000; // 2 minutes\n\n type ComposePsEntry = {\n Service?: string;\n Health?: string;\n State?: string;\n };\n\n const checkHealth = async (): Promise<boolean> => {\n try {\n const { stdout } = await execa(\n \"docker\",\n [...getComposeBaseArgs(ctx), \"ps\", \"--format\", \"json\"],\n {\n cwd: ctx.dir,\n }\n );\n\n const containers = stdout\n .split(\"\\n\")\n .filter(Boolean)\n .map((line) => JSON.parse(line) as ComposePsEntry);\n\n const allHealthy = services.every((service) => {\n const container = containers.find((c) => c.Service === service);\n return (\n container &&\n (container.Health === \"healthy\" || container.State === \"running\")\n );\n });\n\n return allHealthy;\n } catch {\n return false;\n }\n };\n\n const success = await waitFor(checkHealth, {\n timeoutMs: maxWaitMs,\n intervalMs: 2000,\n onProgress: (elapsed) => {\n const seconds = Math.floor(elapsed / 1000);\n spinner.text = `Waiting for services to be healthy... (${seconds}s)`;\n },\n });\n\n if (success) {\n spinner.succeed(\"All services healthy\");\n } else {\n spinner.warn(\"Services taking longer than expected...\");\n console.log(\n chalk.yellow(\n \"\\nā ļø Health check timeout. Services may still be starting.\"\n )\n );\n console.log(\n chalk.gray(\" Run\"),\n chalk.cyan(\"baseboards logs\"),\n chalk.gray(\"to check progress.\")\n );\n }\n}\n\n/**\n * Run database migrations\n */\nasync function runMigrations(ctx: ProjectContext): Promise<void> {\n const spinner = ora(\"Running database migrations...\").start();\n\n try {\n await execa(\n \"docker\",\n [\n ...getComposeBaseArgs(ctx),\n \"exec\",\n \"-T\",\n \"api\",\n \"alembic\",\n \"upgrade\",\n \"head\",\n ],\n {\n cwd: ctx.dir,\n }\n );\n spinner.succeed(\"Database migrations complete\");\n } catch (error) {\n spinner.fail(\"Database migrations failed\");\n\n // Check if this is a password authentication error\n const errorMessage = error instanceof Error ? error.message : String(error);\n const isPasswordError =\n errorMessage.includes(\"password authentication failed\") ||\n errorMessage.includes(\"InvalidPasswordError\");\n\n if (isPasswordError) {\n console.log(\n chalk.red(\n \"\\nā Database password mismatch - cannot connect to existing database\"\n )\n );\n console.log(\n chalk.yellow(\n \" Existing database volumes have a different password than the current configuration.\"\n )\n );\n console.log(chalk.yellow(\"\\n To fix this, choose one of:\"));\n console.log(\n chalk.cyan(\" 1. Start fresh (deletes data):\") +\n chalk.gray(\" baseboards down --volumes && baseboards up\")\n );\n console.log(\n chalk.cyan(\" 2. Start fresh automatically:\") +\n chalk.gray(\" baseboards up --fresh\")\n );\n console.log(\n chalk.gray(\n \"\\n This usually happens when project files were deleted but Docker volumes remain.\"\n )\n );\n } else {\n console.log(\n chalk.yellow(\n \"\\nā ļø Database migrations failed. You may need to run them manually:\"\n )\n );\n console.log(\n chalk.cyan(\" docker compose exec api alembic upgrade head\")\n );\n console.log(chalk.gray(\"\\n Error details:\"));\n console.log(chalk.gray(\" \" + errorMessage));\n }\n\n // Don't throw - app can still start\n }\n}\n\n/**\n * Print success message with URLs and next steps\n */\nfunction printSuccessMessage(\n ctx: ProjectContext,\n detached: boolean,\n hasKeyWarning: boolean\n): void {\n console.log(chalk.green.bold(\"\\n⨠Baseboards is running!\\n\"));\n console.log(\n chalk.cyan(\" š Web:\"),\n chalk.underline(`http://localhost:${ctx.ports.web}`)\n );\n console.log(\n chalk.cyan(\" š API:\"),\n chalk.underline(`http://localhost:${ctx.ports.api}`)\n );\n console.log(\n chalk.cyan(\" š GraphQL:\"),\n chalk.underline(`http://localhost:${ctx.ports.api}/graphql`)\n );\n\n if (hasKeyWarning) {\n console.log(chalk.yellow(\"\\nā ļø Remember to configure provider API keys!\"));\n console.log(chalk.gray(\" Edit:\"), chalk.cyan(\"api/.env\"));\n console.log(\n chalk.gray(\" Docs:\"),\n chalk.cyan(\"https://baseboards.dev/docs/setup\")\n );\n }\n\n console.log(chalk.gray(\"\\nš Commands:\"));\n console.log(chalk.gray(\" Stop:\"), chalk.cyan(\"baseboards down\"));\n console.log(chalk.gray(\" Logs:\"), chalk.cyan(\"baseboards logs\"));\n console.log(chalk.gray(\" Status:\"), chalk.cyan(\"baseboards status\"));\n console.log();\n}\n\n/**\n * Check if Docker volumes exist for this project\n */\nasync function checkForExistingVolumes(): Promise<boolean> {\n try {\n const { stdout } = await execa(\"docker\", [\n \"volume\",\n \"ls\",\n \"--format\",\n \"{{.Name}}\",\n ]);\n const volumes = stdout.split(\"\\n\").filter(Boolean);\n\n // Check for the project-specific database volume\n // Volume name format: baseboards_db-data\n // NOTE: We use \"baseboards\" (not ctx.name) because the compose.yaml template\n // sets `name: ${PROJECT_NAME:-baseboards}` and the PROJECT_NAME env var is only\n // read from docker/.env for service env vars, not for the compose project name itself.\n // So all Baseboards installations use the same \"baseboards\" project name.\n const projectVolumeName = \"baseboards_db-data\";\n return volumes.includes(projectVolumeName);\n } catch {\n // If docker command fails, assume no volumes exist\n return false;\n }\n}\n\n/**\n * Clean up Docker volumes for this project\n */\nasync function cleanupDockerVolumes(ctx: ProjectContext): Promise<void> {\n const spinner = ora(\"Cleaning up Docker volumes...\").start();\n\n try {\n // If compose files exist, use docker compose down -v\n if (ctx.isScaffolded) {\n await execa(\"docker\", [...getComposeBaseArgs(ctx), \"down\", \"-v\"], {\n cwd: ctx.dir,\n });\n } else {\n // If no compose files yet, manually remove the volume by name\n // This handles the case where project was deleted but volumes remain\n const volumesToRemove = [\"baseboards_db-data\", \"baseboards_api-storage\"];\n\n for (const volumeName of volumesToRemove) {\n try {\n await execa(\"docker\", [\"volume\", \"rm\", volumeName]);\n spinner.text = `Removing volume ${volumeName}...`;\n } catch {\n // Volume might not exist, that's okay - it may have been manually removed\n // or never created in the first place\n }\n }\n }\n spinner.succeed(\"Docker volumes cleaned up\");\n } catch (error) {\n spinner.fail(\"Failed to clean up volumes\");\n console.log(\n chalk.yellow(\n \"\\nā ļø Could not clean up volumes automatically. Try manually:\"\n )\n );\n console.log(chalk.cyan(\" docker volume rm baseboards_db-data\"));\n throw error;\n }\n}\n","/**\n * Utility functions for the Baseboards CLI\n */\n\nimport { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport which from \"which\";\nimport type { Prerequisites, ProjectContext } from \"./types.js\";\nimport chalk from \"chalk\";\nimport crypto from \"crypto\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n/**\n * Get the templates directory (bundled with the CLI package)\n */\nexport function getTemplatesDir(): string {\n // In built package, templates are at root level next to dist/\n return path.join(__dirname, \"../templates\");\n}\n\n/**\n * Check system prerequisites\n */\nexport async function checkPrerequisites(): Promise<Prerequisites> {\n const prereqs: Prerequisites = {\n docker: { installed: false },\n node: { installed: true, satisfies: false },\n platform: { name: process.platform },\n };\n\n // Check Docker\n try {\n const dockerPath = await which(\"docker\");\n prereqs.docker.installed = !!dockerPath;\n\n if (dockerPath) {\n const { stdout } = await execa(\"docker\", [\"--version\"]);\n const match = stdout.match(/Docker version ([\\d.]+)/);\n if (match) {\n prereqs.docker.version = match[1];\n }\n\n // Check Docker Compose\n try {\n const { stdout: composeStdout } = await execa(\"docker\", [\n \"compose\",\n \"version\",\n ]);\n const composeMatch = composeStdout.match(/version v?([\\d.]+)/);\n if (composeMatch) {\n prereqs.docker.composeVersion = composeMatch[1];\n }\n } catch (e) {\n // Compose not available\n }\n }\n } catch (e) {\n // Docker not installed\n }\n\n // Check Node version\n const nodeVersion = process.version.replace(\"v\", \"\");\n prereqs.node.version = nodeVersion;\n\n const majorVersion = parseInt(nodeVersion.split(\".\")[0], 10);\n prereqs.node.satisfies = majorVersion >= 20;\n\n // Check if WSL\n if (process.platform === \"linux\") {\n try {\n const { stdout } = await execa(\"uname\", [\"-r\"]);\n if (\n stdout.toLowerCase().includes(\"microsoft\") ||\n stdout.toLowerCase().includes(\"wsl\")\n ) {\n prereqs.platform.isWSL = true;\n }\n } catch (e) {\n // Not WSL or can't determine\n }\n }\n\n return prereqs;\n}\n\n/**\n * Assert that prerequisites are met, or exit with helpful error\n */\nexport async function assertPrerequisites(): Promise<void> {\n const prereqs = await checkPrerequisites();\n\n const errors: string[] = [];\n\n if (!prereqs.docker.installed) {\n errors.push(\n \"š³ Docker is not installed.\",\n \" Install from: https://docs.docker.com/get-docker/\"\n );\n } else if (!prereqs.docker.composeVersion) {\n errors.push(\n \"š³ Docker Compose (v2) is not available.\",\n \" Update Docker to get Compose v2: https://docs.docker.com/compose/install/\"\n );\n }\n\n if (!prereqs.node.satisfies) {\n errors.push(\n `ā ļø Node.js ${prereqs.node.version} is too old (need v20+).`,\n \" Install from: https://nodejs.org/\"\n );\n }\n\n if (errors.length > 0) {\n console.error(chalk.red(\"\\nā Prerequisites not met:\\n\"));\n errors.forEach((err) => console.error(chalk.yellow(err)));\n console.error(\"\");\n process.exit(1);\n }\n}\n\n/**\n * Check if a directory is already scaffolded\n */\nexport function isScaffolded(dir: string): boolean {\n // Check for key files that indicate scaffolding\n const keyFiles = [\"compose.yaml\", \"web/package.json\", \"api/pyproject.toml\"];\n\n return keyFiles.every((file) => fs.existsSync(path.join(dir, file)));\n}\n\n/**\n * Find an available port\n */\nexport async function findAvailablePort(\n preferred: number,\n maxAttempts = 50\n): Promise<number> {\n for (let port = preferred; port < preferred + maxAttempts; port++) {\n if (await isPortAvailable(port)) {\n return port;\n }\n }\n throw new Error(`No available port found near ${preferred}`);\n}\n\n/**\n * Check if a port is available\n */\nasync function isPortAvailable(port: number): Promise<boolean> {\n const { createServer } = await import(\"net\");\n return new Promise((resolve) => {\n const server = createServer();\n server.once(\"error\", () => resolve(false));\n server.once(\"listening\", () => {\n server.close();\n resolve(true);\n });\n server.listen(port);\n });\n}\n\n/**\n * Generate a random secure string\n */\nexport function generateSecret(length = 32): string {\n return crypto.randomBytes(length).toString(\"hex\");\n}\n\n/**\n * Generate a random password\n */\nexport function generatePassword(length = 24): string {\n const charset =\n \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#%^&*\";\n let password = \"\";\n const bytes = crypto.randomBytes(length);\n\n for (let i = 0; i < length; i++) {\n password += charset[bytes[i] % charset.length];\n }\n\n return password;\n}\n\n/**\n * Parse custom ports string (e.g., \"web=3300 api=8800\")\n */\nexport function parsePortsOption(portsStr: string): Partial<{\n web: number;\n api: number;\n db: number;\n redis: number;\n}> {\n const ports: any = {};\n const pairs = portsStr.split(/\\s+/);\n\n for (const pair of pairs) {\n const [service, port] = pair.split(\"=\");\n const portNum = parseInt(port, 10);\n if (\n service &&\n [\"web\", \"api\", \"db\", \"redis\"].includes(service) &&\n !isNaN(portNum)\n ) {\n ports[service] = portNum;\n }\n }\n\n return ports;\n}\n\n/**\n * Read package.json version\n */\nexport function getCliVersion(): string {\n const packagePath = path.join(__dirname, \"../package.json\");\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf-8\"));\n return packageJson.version;\n}\n\n/**\n * Detect missing provider API keys in .env file\n */\nexport function detectMissingProviderKeys(envPath: string): string[] {\n if (!fs.existsSync(envPath)) {\n return [];\n }\n\n const envContent = fs.readFileSync(envPath, \"utf-8\");\n const providerKeys = [\n \"REPLICATE_API_TOKEN\",\n \"FAL_KEY\",\n \"KIE_API_KEY\",\n \"OPENAI_API_KEY\",\n \"GOOGLE_API_KEY\",\n ];\n\n const missingKeys: string[] = [];\n\n for (const key of providerKeys) {\n const regex = new RegExp(`^${key}=(.*)$`, \"m\");\n const match = envContent.match(regex);\n\n // Key is missing if not found or if value is empty\n if (!match || !match[1] || match[1].trim() === \"\") {\n missingKeys.push(key);\n }\n }\n\n // If all keys are missing, user hasn't configured any\n if (missingKeys.length === providerKeys.length) {\n return missingKeys;\n }\n\n return [];\n}\n\n/**\n * Wait for a condition with timeout\n */\nexport async function waitFor(\n condition: () => Promise<boolean>,\n options: {\n timeoutMs: number;\n intervalMs?: number;\n onProgress?: (elapsed: number) => void;\n }\n): Promise<boolean> {\n const { timeoutMs, intervalMs = 1000, onProgress } = options;\n const startTime = Date.now();\n\n while (Date.now() - startTime < timeoutMs) {\n if (await condition()) {\n return true;\n }\n\n if (onProgress) {\n onProgress(Date.now() - startTime);\n }\n\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n\n return false;\n}\n","/**\n * down command - Stop Baseboards\n */\n\nimport { execa } from 'execa';\nimport path from 'path';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport type { DownOptions } from '../types.js';\nimport { isScaffolded } from '../utils.js';\n\nexport async function down(directory: string, options: DownOptions): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n const spinner = ora('Stopping services...').start();\n\n const args = ['compose', 'down'];\n if (options.volumes) {\n args.push('--volumes');\n }\n\n try {\n await execa('docker', args, {\n cwd: dir,\n });\n\n spinner.succeed('Services stopped');\n\n if (options.volumes) {\n console.log(chalk.yellow('ā ļø Volumes removed (database data deleted)'));\n }\n } catch (error: any) {\n spinner.fail('Failed to stop services');\n throw error;\n }\n}\n","/**\n * logs command - View service logs\n */\n\nimport { execa } from 'execa';\nimport path from 'path';\nimport chalk from 'chalk';\nimport type { LogsOptions } from '../types.js';\nimport { isScaffolded } from '../utils.js';\n\nexport async function logs(\n directory: string,\n services: string[],\n options: LogsOptions\n): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n const args = ['compose', 'logs'];\n\n if (options.follow) {\n args.push('--follow');\n }\n\n if (options.since) {\n args.push('--since', options.since);\n }\n\n if (options.tail) {\n args.push('--tail', options.tail);\n }\n\n // Add specific services if provided\n if (services.length > 0) {\n args.push(...services);\n }\n\n try {\n await execa('docker', args, {\n cwd: dir,\n stdio: 'inherit',\n });\n } catch (error: any) {\n // Ctrl+C is expected, don't treat as error\n if (error.signal !== 'SIGINT') {\n throw error;\n }\n }\n}\n","/**\n * status command - Show service status\n */\n\nimport { execa } from 'execa';\nimport path from 'path';\nimport chalk from 'chalk';\nimport { isScaffolded } from '../utils.js';\n\nexport async function status(directory: string): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n console.log(chalk.blue.bold('\\nš Service Status\\n'));\n\n try {\n await execa('docker', ['compose', 'ps'], {\n cwd: dir,\n stdio: 'inherit',\n });\n } catch (error: any) {\n console.error(chalk.red('\\nā Failed to get status'));\n throw error;\n }\n}\n","/**\n * clean command - Clean up Docker resources\n */\n\nimport { execa } from 'execa';\nimport path from 'path';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport prompts from 'prompts';\nimport type { CleanOptions } from '../types.js';\nimport { isScaffolded } from '../utils.js';\n\nexport async function clean(\n directory: string,\n options: CleanOptions\n): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n if (options.hard) {\n console.log(chalk.yellow('\\nā ļø WARNING: This will delete:'));\n console.log(chalk.yellow(' ⢠All containers'));\n console.log(chalk.yellow(' ⢠All volumes (database data will be lost)'));\n console.log(chalk.yellow(' ⢠All images'));\n\n const response = await prompts({\n type: 'confirm',\n name: 'confirmed',\n message: 'Are you sure?',\n initial: false,\n });\n\n if (!response.confirmed) {\n console.log(chalk.gray('\\nCancelled'));\n return;\n }\n }\n\n const spinner = ora('Cleaning up...').start();\n\n try {\n // Stop containers\n await execa('docker', ['compose', 'down', '--volumes', '--remove-orphans'], {\n cwd: dir,\n });\n\n if (options.hard) {\n // Remove images\n try {\n const { stdout } = await execa('docker', ['compose', 'images', '-q'], {\n cwd: dir,\n });\n\n const imageIds = stdout.split('\\n').filter(Boolean);\n if (imageIds.length > 0) {\n await execa('docker', ['rmi', ...imageIds]);\n }\n } catch (e) {\n // Images might not exist or already removed\n }\n }\n\n spinner.succeed('Cleanup complete');\n\n if (options.hard) {\n console.log(chalk.green('\\n⨠All Docker resources removed'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to start fresh.'));\n } else {\n console.log(chalk.green('\\n⨠Containers and volumes removed'));\n }\n } catch (error: any) {\n spinner.fail('Cleanup failed');\n throw error;\n }\n}\n","/**\n * update command - Update Baseboards to latest version\n */\n\nimport path from 'path';\nimport chalk from 'chalk';\nimport type { UpdateOptions } from '../types.js';\nimport { isScaffolded } from '../utils.js';\n\nexport async function update(\n directory: string,\n options: UpdateOptions\n): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n if (!isScaffolded(dir)) {\n console.error(chalk.red('\\nā Error: Not a Baseboards project'));\n console.log(chalk.gray(' Run'), chalk.cyan('baseboards up'), chalk.gray('to scaffold a project first.'));\n process.exit(1);\n }\n\n console.log(chalk.blue.bold('\\nš Update Command\\n'));\n console.log(chalk.yellow('ā ļø This feature is coming soon!'));\n console.log(chalk.gray('\\nFor now, to update:'));\n console.log(chalk.gray('1. Update the CLI:'), chalk.cyan('npm install -g @weirdfingers/baseboards@latest'));\n console.log(chalk.gray('2. Pull new images:'), chalk.cyan('docker compose pull'));\n console.log(chalk.gray('3. Restart:'), chalk.cyan('baseboards down && baseboards up'));\n console.log();\n\n // TODO: Implement update logic:\n // 1. Check for new version on npm\n // 2. Scan for modified source files (git diff or timestamp check)\n // 3. If no modifications:\n // - Copy new templates (preserving config)\n // - Pull new Docker images\n // - Update package.json versions\n // 4. If modifications detected:\n // - Warn user\n // - Offer git-based merge if repo detected\n // - Create backup otherwise\n // 5. Preserve:\n // - All .env files\n // - config/*.yaml files\n // - data/storage/ directory\n}\n","/**\n * doctor command - Run diagnostics\n */\n\nimport path from 'path';\nimport fs from 'fs-extra';\nimport chalk from 'chalk';\nimport { checkPrerequisites, isScaffolded, detectMissingProviderKeys, getCliVersion } from '../utils.js';\n\nexport async function doctor(directory: string): Promise<void> {\n const dir = path.resolve(process.cwd(), directory);\n\n console.log(chalk.blue.bold('\\n𩺠Baseboards Diagnostics\\n'));\n\n // CLI Version\n console.log(chalk.cyan('CLI Version:'), getCliVersion());\n\n // Prerequisites\n console.log(chalk.cyan('\\nš Prerequisites:'));\n const prereqs = await checkPrerequisites();\n\n console.log(\n chalk.gray(' Node.js:'),\n prereqs.node.installed\n ? prereqs.node.satisfies\n ? chalk.green(`ā v${prereqs.node.version}`)\n : chalk.yellow(`ā ļø v${prereqs.node.version} (need v20+)`)\n : chalk.red('ā Not installed')\n );\n\n console.log(\n chalk.gray(' Docker:'),\n prereqs.docker.installed\n ? chalk.green(`ā v${prereqs.docker.version}`)\n : chalk.red('ā Not installed')\n );\n\n if (prereqs.docker.composeVersion) {\n console.log(\n chalk.gray(' Docker Compose:'),\n chalk.green(`ā v${prereqs.docker.composeVersion}`)\n );\n } else if (prereqs.docker.installed) {\n console.log(chalk.gray(' Docker Compose:'), chalk.red('ā Not available'));\n }\n\n console.log(chalk.gray(' Platform:'), prereqs.platform.name);\n if (prereqs.platform.isWSL) {\n console.log(chalk.gray(' WSL:'), chalk.blue('ā Detected'));\n }\n\n // Project info\n console.log(chalk.cyan('\\nš Project:'));\n const scaffolded = isScaffolded(dir);\n console.log(\n chalk.gray(' Scaffolded:'),\n scaffolded ? chalk.green('ā Yes') : chalk.yellow('ā No')\n );\n\n if (scaffolded) {\n console.log(chalk.gray(' Directory:'), dir);\n\n // Check for key files\n const webPkg = path.join(dir, 'web/package.json');\n const apiPkg = path.join(dir, 'api/pyproject.toml');\n const composeFile = path.join(dir, 'compose.yaml');\n\n console.log(\n chalk.gray(' Web package:'),\n fs.existsSync(webPkg) ? chalk.green('ā') : chalk.red('ā')\n );\n console.log(\n chalk.gray(' API package:'),\n fs.existsSync(apiPkg) ? chalk.green('ā') : chalk.red('ā')\n );\n console.log(\n chalk.gray(' Compose file:'),\n fs.existsSync(composeFile) ? chalk.green('ā') : chalk.red('ā')\n );\n\n // Check .env files\n console.log(chalk.cyan('\\nš Environment:'));\n const webEnv = path.join(dir, 'web/.env');\n const apiEnv = path.join(dir, 'api/.env');\n const dockerEnv = path.join(dir, 'docker/.env');\n\n console.log(\n chalk.gray(' Web .env:'),\n fs.existsSync(webEnv) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n console.log(\n chalk.gray(' API .env:'),\n fs.existsSync(apiEnv) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n console.log(\n chalk.gray(' Docker .env:'),\n fs.existsSync(dockerEnv) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n\n // Check provider keys\n if (fs.existsSync(apiEnv)) {\n const missingKeys = detectMissingProviderKeys(apiEnv);\n if (missingKeys.length > 0) {\n console.log(\n chalk.gray(' Provider keys:'),\n chalk.yellow(`ā ļø ${missingKeys.length} missing`)\n );\n console.log(chalk.gray(' Missing:'), missingKeys.map(k => chalk.cyan(k)).join(', '));\n } else {\n console.log(chalk.gray(' Provider keys:'), chalk.green('ā Configured'));\n }\n }\n\n // Check config files\n console.log(chalk.cyan('\\nāļø Configuration:'));\n const generatorsYaml = path.join(dir, 'api/config/generators.yaml');\n const storageYaml = path.join(dir, 'api/config/storage_config.yaml');\n\n console.log(\n chalk.gray(' generators.yaml:'),\n fs.existsSync(generatorsYaml) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n console.log(\n chalk.gray(' storage_config.yaml:'),\n fs.existsSync(storageYaml) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n\n // Check storage directory\n const storageDir = path.join(dir, 'data/storage');\n console.log(\n chalk.gray(' Storage directory:'),\n fs.existsSync(storageDir) ? chalk.green('ā') : chalk.yellow('ā Missing')\n );\n }\n\n // Recommendations\n console.log(chalk.cyan('\\nš” Recommendations:'));\n const recommendations: string[] = [];\n\n if (!prereqs.node.satisfies) {\n recommendations.push('Upgrade Node.js to v20 or higher');\n }\n\n if (!prereqs.docker.installed) {\n recommendations.push('Install Docker Desktop: https://docs.docker.com/get-docker/');\n } else if (!prereqs.docker.composeVersion) {\n recommendations.push('Update Docker to get Compose v2');\n }\n\n if (!scaffolded) {\n recommendations.push('Run ' + chalk.cyan('baseboards up') + ' to scaffold a project');\n }\n\n if (recommendations.length === 0) {\n console.log(chalk.green(' ā Everything looks good!'));\n } else {\n recommendations.forEach((rec) => console.log(chalk.yellow(' ā¢'), rec));\n }\n\n console.log();\n}\n"],"mappings":"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","names":["fileURLToPath","chalk","execa","fs","path","chalk","packageJson","chalk","path","fs","execa","execa","path","chalk","ora","path","chalk","ora","execa","execa","path","chalk","path","chalk","execa","execa","path","chalk","path","chalk","execa","execa","path","chalk","ora","prompts","path","chalk","prompts","ora","execa","path","chalk","path","chalk","path","fs","chalk","path","chalk","fs","__filename","fileURLToPath","__dirname","chalk"]}
|
package/package.json
CHANGED
package/templates/README.md
CHANGED
|
@@ -19,11 +19,13 @@ This is a self-hosted Baseboards installation, scaffolded by the Baseboards CLI.
|
|
|
19
19
|
# Get your API keys from:
|
|
20
20
|
# - Replicate: https://replicate.com/account/api-tokens
|
|
21
21
|
# - FAL: https://fal.ai/dashboard/keys
|
|
22
|
+
# - KIE: https://kie.ai/dashboard
|
|
22
23
|
# - OpenAI: https://platform.openai.com/api-keys
|
|
23
24
|
# - Google: https://makersuite.google.com/app/apikey
|
|
24
25
|
|
|
25
26
|
REPLICATE_API_KEY=r8_...
|
|
26
27
|
FAL_KEY=...
|
|
28
|
+
KIE_API_KEY=...
|
|
27
29
|
OPENAI_API_KEY=sk-...
|
|
28
30
|
GOOGLE_API_KEY=...
|
|
29
31
|
```
|