@weirdfingers/baseboards 0.9.5 → 0.9.7
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 +561 -469
- package/dist/index.js.map +1 -1
- package/package.json +2 -5
- package/templates/README.md +0 -122
- package/templates/api/.env.example +0 -65
- package/templates/api/ARTIFACT_RESOLUTION_GUIDE.md +0 -148
- package/templates/api/Dockerfile +0 -32
- package/templates/api/README.md +0 -264
- package/templates/api/alembic/env.py +0 -114
- package/templates/api/alembic/script.py.mako +0 -28
- package/templates/api/alembic/versions/20250101_000000_initial_schema.py +0 -506
- package/templates/api/alembic/versions/20251022_174729_remove_provider_name_from_generations.py +0 -75
- package/templates/api/alembic/versions/20251023_165852_switch_to_declarative_base_and_mapping.py +0 -467
- package/templates/api/alembic/versions/20251202_000000_add_artifact_lineage.py +0 -134
- package/templates/api/alembic/versions/2025925_62735_add_seed_data_for_default_tenant.py +0 -88
- package/templates/api/alembic.ini +0 -36
- package/templates/api/config/generators.yaml +0 -237
- package/templates/api/config/storage_config.yaml +0 -26
- package/templates/api/docs/ADDING_GENERATORS.md +0 -409
- package/templates/api/docs/GENERATORS_API.md +0 -502
- package/templates/api/docs/MIGRATIONS.md +0 -472
- package/templates/api/docs/TESTING_LIVE_APIS.md +0 -417
- package/templates/api/docs/storage_providers.md +0 -337
- package/templates/api/pyproject.toml +0 -205
- package/templates/api/src/boards/__init__.py +0 -10
- package/templates/api/src/boards/api/app.py +0 -172
- package/templates/api/src/boards/api/auth.py +0 -75
- package/templates/api/src/boards/api/endpoints/__init__.py +0 -3
- package/templates/api/src/boards/api/endpoints/jobs.py +0 -76
- package/templates/api/src/boards/api/endpoints/setup.py +0 -505
- package/templates/api/src/boards/api/endpoints/sse.py +0 -129
- package/templates/api/src/boards/api/endpoints/storage.py +0 -155
- package/templates/api/src/boards/api/endpoints/tenant_registration.py +0 -296
- package/templates/api/src/boards/api/endpoints/uploads.py +0 -149
- package/templates/api/src/boards/api/endpoints/webhooks.py +0 -13
- package/templates/api/src/boards/auth/__init__.py +0 -15
- package/templates/api/src/boards/auth/adapters/__init__.py +0 -27
- package/templates/api/src/boards/auth/adapters/auth0.py +0 -220
- package/templates/api/src/boards/auth/adapters/base.py +0 -73
- package/templates/api/src/boards/auth/adapters/clerk.py +0 -172
- package/templates/api/src/boards/auth/adapters/jwt.py +0 -122
- package/templates/api/src/boards/auth/adapters/none.py +0 -102
- package/templates/api/src/boards/auth/adapters/oidc.py +0 -284
- package/templates/api/src/boards/auth/adapters/supabase.py +0 -110
- package/templates/api/src/boards/auth/context.py +0 -35
- package/templates/api/src/boards/auth/factory.py +0 -129
- package/templates/api/src/boards/auth/middleware.py +0 -221
- package/templates/api/src/boards/auth/provisioning.py +0 -129
- package/templates/api/src/boards/auth/tenant_extraction.py +0 -278
- package/templates/api/src/boards/cli.py +0 -354
- package/templates/api/src/boards/config.py +0 -131
- package/templates/api/src/boards/database/__init__.py +0 -7
- package/templates/api/src/boards/database/cli.py +0 -110
- package/templates/api/src/boards/database/connection.py +0 -292
- package/templates/api/src/boards/database/models.py +0 -19
- package/templates/api/src/boards/database/seed_data.py +0 -182
- package/templates/api/src/boards/dbmodels/__init__.py +0 -441
- package/templates/api/src/boards/generators/__init__.py +0 -57
- package/templates/api/src/boards/generators/artifact_resolution.py +0 -405
- package/templates/api/src/boards/generators/artifacts.py +0 -53
- package/templates/api/src/boards/generators/base.py +0 -144
- package/templates/api/src/boards/generators/implementations/__init__.py +0 -14
- package/templates/api/src/boards/generators/implementations/fal/__init__.py +0 -25
- package/templates/api/src/boards/generators/implementations/fal/audio/__init__.py +0 -23
- package/templates/api/src/boards/generators/implementations/fal/audio/beatoven_music_generation.py +0 -171
- package/templates/api/src/boards/generators/implementations/fal/audio/beatoven_sound_effect_generation.py +0 -167
- package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_text_to_speech.py +0 -176
- package/templates/api/src/boards/generators/implementations/fal/audio/chatterbox_tts_turbo.py +0 -195
- package/templates/api/src/boards/generators/implementations/fal/audio/elevenlabs_sound_effects_v2.py +0 -194
- package/templates/api/src/boards/generators/implementations/fal/audio/elevenlabs_tts_eleven_v3.py +0 -209
- package/templates/api/src/boards/generators/implementations/fal/audio/fal_elevenlabs_tts_turbo_v2_5.py +0 -206
- package/templates/api/src/boards/generators/implementations/fal/audio/fal_minimax_speech_26_hd.py +0 -237
- package/templates/api/src/boards/generators/implementations/fal/audio/minimax_music_v2.py +0 -173
- package/templates/api/src/boards/generators/implementations/fal/audio/minimax_speech_2_6_turbo.py +0 -221
- package/templates/api/src/boards/generators/implementations/fal/image/__init__.py +0 -63
- package/templates/api/src/boards/generators/implementations/fal/image/bytedance_seedream_v45_edit.py +0 -219
- package/templates/api/src/boards/generators/implementations/fal/image/clarity_upscaler.py +0 -220
- package/templates/api/src/boards/generators/implementations/fal/image/crystal_upscaler.py +0 -173
- package/templates/api/src/boards/generators/implementations/fal/image/fal_ideogram_character.py +0 -227
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2.py +0 -203
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2_edit.py +0 -230
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2_pro.py +0 -204
- package/templates/api/src/boards/generators/implementations/fal/image/flux_2_pro_edit.py +0 -221
- package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_kontext.py +0 -216
- package/templates/api/src/boards/generators/implementations/fal/image/flux_pro_ultra.py +0 -197
- package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image.py +0 -177
- package/templates/api/src/boards/generators/implementations/fal/image/gemini_25_flash_image_edit.py +0 -208
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_15_edit.py +0 -216
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_5.py +0 -177
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_edit_image.py +0 -182
- package/templates/api/src/boards/generators/implementations/fal/image/gpt_image_1_mini.py +0 -167
- package/templates/api/src/boards/generators/implementations/fal/image/ideogram_character_edit.py +0 -299
- package/templates/api/src/boards/generators/implementations/fal/image/ideogram_v2.py +0 -190
- package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview.py +0 -191
- package/templates/api/src/boards/generators/implementations/fal/image/imagen4_preview_fast.py +0 -179
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana.py +0 -183
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_edit.py +0 -212
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_pro.py +0 -179
- package/templates/api/src/boards/generators/implementations/fal/image/nano_banana_pro_edit.py +0 -226
- package/templates/api/src/boards/generators/implementations/fal/image/qwen_image.py +0 -249
- package/templates/api/src/boards/generators/implementations/fal/image/qwen_image_edit.py +0 -244
- package/templates/api/src/boards/generators/implementations/fal/image/reve_edit.py +0 -178
- package/templates/api/src/boards/generators/implementations/fal/image/reve_text_to_image.py +0 -155
- package/templates/api/src/boards/generators/implementations/fal/image/seedream_v45_text_to_image.py +0 -180
- package/templates/api/src/boards/generators/implementations/fal/utils.py +0 -61
- package/templates/api/src/boards/generators/implementations/fal/video/__init__.py +0 -77
- package/templates/api/src/boards/generators/implementations/fal/video/bytedance_seedance_v1_pro_text_to_video.py +0 -209
- package/templates/api/src/boards/generators/implementations/fal/video/creatify_lipsync.py +0 -161
- package/templates/api/src/boards/generators/implementations/fal/video/fal_bytedance_seedance_v1_pro_image_to_video.py +0 -222
- package/templates/api/src/boards/generators/implementations/fal/video/fal_minimax_hailuo_02_standard_text_to_video.py +0 -152
- package/templates/api/src/boards/generators/implementations/fal/video/fal_pixverse_lipsync.py +0 -197
- package/templates/api/src/boards/generators/implementations/fal/video/fal_sora_2_text_to_video.py +0 -173
- package/templates/api/src/boards/generators/implementations/fal/video/infinitalk.py +0 -221
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_pro.py +0 -168
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_ai_avatar_v2_standard.py +0 -159
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_v2_5_turbo_pro_image_to_video.py +0 -175
- package/templates/api/src/boards/generators/implementations/fal/video/kling_video_v2_5_turbo_pro_text_to_video.py +0 -168
- package/templates/api/src/boards/generators/implementations/fal/video/minimax_hailuo_2_3_pro_image_to_video.py +0 -153
- package/templates/api/src/boards/generators/implementations/fal/video/sora2_image_to_video.py +0 -172
- package/templates/api/src/boards/generators/implementations/fal/video/sora_2_image_to_video_pro.py +0 -175
- package/templates/api/src/boards/generators/implementations/fal/video/sora_2_text_to_video_pro.py +0 -163
- package/templates/api/src/boards/generators/implementations/fal/video/sync_lipsync_v2.py +0 -167
- package/templates/api/src/boards/generators/implementations/fal/video/sync_lipsync_v2_pro.py +0 -155
- package/templates/api/src/boards/generators/implementations/fal/video/veed_fabric_1_0.py +0 -180
- package/templates/api/src/boards/generators/implementations/fal/video/veed_lipsync.py +0 -174
- package/templates/api/src/boards/generators/implementations/fal/video/veo3.py +0 -194
- package/templates/api/src/boards/generators/implementations/fal/video/veo31.py +0 -190
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast.py +0 -190
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_fast_image_to_video.py +0 -191
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_first_last_frame_to_video.py +0 -187
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_image_to_video.py +0 -183
- package/templates/api/src/boards/generators/implementations/fal/video/veo31_reference_to_video.py +0 -172
- package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_image_to_video.py +0 -212
- package/templates/api/src/boards/generators/implementations/fal/video/wan_25_preview_text_to_video.py +0 -208
- package/templates/api/src/boards/generators/implementations/fal/video/wan_pro_image_to_video.py +0 -158
- package/templates/api/src/boards/generators/implementations/kie/__init__.py +0 -11
- package/templates/api/src/boards/generators/implementations/kie/base.py +0 -316
- package/templates/api/src/boards/generators/implementations/kie/image/__init__.py +0 -3
- package/templates/api/src/boards/generators/implementations/kie/image/nano_banana_edit.py +0 -190
- package/templates/api/src/boards/generators/implementations/kie/utils.py +0 -98
- package/templates/api/src/boards/generators/implementations/kie/video/__init__.py +0 -8
- package/templates/api/src/boards/generators/implementations/kie/video/veo3.py +0 -161
- package/templates/api/src/boards/generators/implementations/openai/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/openai/audio/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/openai/audio/whisper.py +0 -69
- package/templates/api/src/boards/generators/implementations/openai/image/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/openai/image/dalle3.py +0 -96
- package/templates/api/src/boards/generators/implementations/replicate/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/replicate/image/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/replicate/image/flux_pro.py +0 -88
- package/templates/api/src/boards/generators/implementations/replicate/video/__init__.py +0 -1
- package/templates/api/src/boards/generators/implementations/replicate/video/lipsync.py +0 -73
- package/templates/api/src/boards/generators/loader.py +0 -253
- package/templates/api/src/boards/generators/registry.py +0 -114
- package/templates/api/src/boards/generators/resolution.py +0 -632
- package/templates/api/src/boards/generators/testmods/class_gen.py +0 -34
- package/templates/api/src/boards/generators/testmods/import_side_effect.py +0 -35
- package/templates/api/src/boards/graphql/__init__.py +0 -7
- package/templates/api/src/boards/graphql/access_control.py +0 -136
- package/templates/api/src/boards/graphql/mutations/root.py +0 -148
- package/templates/api/src/boards/graphql/queries/root.py +0 -116
- package/templates/api/src/boards/graphql/resolvers/__init__.py +0 -8
- package/templates/api/src/boards/graphql/resolvers/auth.py +0 -12
- package/templates/api/src/boards/graphql/resolvers/board.py +0 -1053
- package/templates/api/src/boards/graphql/resolvers/generation.py +0 -666
- package/templates/api/src/boards/graphql/resolvers/generator.py +0 -50
- package/templates/api/src/boards/graphql/resolvers/lineage.py +0 -381
- package/templates/api/src/boards/graphql/resolvers/upload.py +0 -463
- package/templates/api/src/boards/graphql/resolvers/user.py +0 -25
- package/templates/api/src/boards/graphql/schema.py +0 -81
- package/templates/api/src/boards/graphql/types/board.py +0 -102
- package/templates/api/src/boards/graphql/types/generation.py +0 -166
- package/templates/api/src/boards/graphql/types/generator.py +0 -17
- package/templates/api/src/boards/graphql/types/user.py +0 -47
- package/templates/api/src/boards/jobs/repository.py +0 -153
- package/templates/api/src/boards/logging.py +0 -195
- package/templates/api/src/boards/middleware.py +0 -339
- package/templates/api/src/boards/progress/__init__.py +0 -4
- package/templates/api/src/boards/progress/models.py +0 -25
- package/templates/api/src/boards/progress/publisher.py +0 -64
- package/templates/api/src/boards/py.typed +0 -0
- package/templates/api/src/boards/redis_pool.py +0 -118
- package/templates/api/src/boards/storage/__init__.py +0 -52
- package/templates/api/src/boards/storage/base.py +0 -363
- package/templates/api/src/boards/storage/config.py +0 -187
- package/templates/api/src/boards/storage/factory.py +0 -288
- package/templates/api/src/boards/storage/implementations/__init__.py +0 -27
- package/templates/api/src/boards/storage/implementations/gcs.py +0 -340
- package/templates/api/src/boards/storage/implementations/local.py +0 -201
- package/templates/api/src/boards/storage/implementations/s3.py +0 -294
- package/templates/api/src/boards/storage/implementations/supabase.py +0 -218
- package/templates/api/src/boards/tenant_isolation.py +0 -446
- package/templates/api/src/boards/validation.py +0 -262
- package/templates/api/src/boards/workers/__init__.py +0 -1
- package/templates/api/src/boards/workers/actors.py +0 -274
- package/templates/api/src/boards/workers/cli.py +0 -125
- package/templates/api/src/boards/workers/context.py +0 -348
- package/templates/api/src/boards/workers/middleware.py +0 -58
- package/templates/api/src/py.typed +0 -0
- package/templates/compose.web.yaml +0 -35
- package/templates/compose.yaml +0 -116
- package/templates/docker/env.example +0 -23
- package/templates/web/.env.example +0 -28
- package/templates/web/Dockerfile +0 -51
- package/templates/web/components.json +0 -22
- package/templates/web/imageLoader.js +0 -18
- package/templates/web/next-env.d.ts +0 -5
- package/templates/web/next.config.js +0 -36
- package/templates/web/package.json +0 -41
- package/templates/web/postcss.config.mjs +0 -7
- package/templates/web/public/favicon.ico +0 -0
- package/templates/web/src/app/boards/[boardId]/page.tsx +0 -353
- package/templates/web/src/app/globals.css +0 -123
- package/templates/web/src/app/layout.tsx +0 -31
- package/templates/web/src/app/lineage/[generationId]/page.tsx +0 -235
- package/templates/web/src/app/page.tsx +0 -35
- package/templates/web/src/app/providers.tsx +0 -18
- package/templates/web/src/components/boards/ArtifactInputSlots.tsx +0 -206
- package/templates/web/src/components/boards/ArtifactPreview.tsx +0 -466
- package/templates/web/src/components/boards/GenerationGrid.tsx +0 -282
- package/templates/web/src/components/boards/GenerationInput.tsx +0 -370
- package/templates/web/src/components/boards/GeneratorSelector.tsx +0 -272
- package/templates/web/src/components/boards/UploadArtifact.tsx +0 -563
- package/templates/web/src/components/header.tsx +0 -32
- package/templates/web/src/components/theme-provider.tsx +0 -10
- package/templates/web/src/components/theme-toggle.tsx +0 -75
- package/templates/web/src/components/ui/alert-dialog.tsx +0 -157
- package/templates/web/src/components/ui/button.tsx +0 -58
- package/templates/web/src/components/ui/card.tsx +0 -92
- package/templates/web/src/components/ui/dropdown-menu.tsx +0 -200
- package/templates/web/src/components/ui/navigation-menu.tsx +0 -168
- package/templates/web/src/components/ui/toast.tsx +0 -128
- package/templates/web/src/components/ui/toaster.tsx +0 -35
- package/templates/web/src/components/ui/use-toast.ts +0 -187
- package/templates/web/src/hooks/useGeneratorMRU.ts +0 -57
- package/templates/web/src/lib/utils.ts +0 -6
- package/templates/web/tsconfig.json +0 -41
package/dist/index.js
CHANGED
|
@@ -3218,8 +3218,8 @@ var require_utils = __commonJS({
|
|
|
3218
3218
|
}
|
|
3219
3219
|
return ind;
|
|
3220
3220
|
}
|
|
3221
|
-
function removeDotSegments(
|
|
3222
|
-
let input =
|
|
3221
|
+
function removeDotSegments(path18) {
|
|
3222
|
+
let input = path18;
|
|
3223
3223
|
const output = [];
|
|
3224
3224
|
let nextSlash = -1;
|
|
3225
3225
|
let len = 0;
|
|
@@ -3418,8 +3418,8 @@ var require_schemes = __commonJS({
|
|
|
3418
3418
|
wsComponent.secure = void 0;
|
|
3419
3419
|
}
|
|
3420
3420
|
if (wsComponent.resourceName) {
|
|
3421
|
-
const [
|
|
3422
|
-
wsComponent.path =
|
|
3421
|
+
const [path18, query] = wsComponent.resourceName.split("?");
|
|
3422
|
+
wsComponent.path = path18 && path18 !== "/" ? path18 : void 0;
|
|
3423
3423
|
wsComponent.query = query;
|
|
3424
3424
|
wsComponent.resourceName = void 0;
|
|
3425
3425
|
}
|
|
@@ -6473,13 +6473,13 @@ import { Command } from "commander";
|
|
|
6473
6473
|
import { readFileSync } from "fs";
|
|
6474
6474
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6475
6475
|
import { dirname, join } from "path";
|
|
6476
|
-
import
|
|
6476
|
+
import chalk14 from "chalk";
|
|
6477
6477
|
|
|
6478
6478
|
// src/commands/up.ts
|
|
6479
|
-
import { execa as
|
|
6480
|
-
import
|
|
6481
|
-
import
|
|
6482
|
-
import
|
|
6479
|
+
import { execa as execa3 } from "execa";
|
|
6480
|
+
import fs6 from "fs-extra";
|
|
6481
|
+
import path6 from "path";
|
|
6482
|
+
import chalk3 from "chalk";
|
|
6483
6483
|
import ora2 from "ora";
|
|
6484
6484
|
import prompts2 from "prompts";
|
|
6485
6485
|
|
|
@@ -6709,41 +6709,120 @@ async function execAsync(command, options) {
|
|
|
6709
6709
|
return execa(cmd, args, options);
|
|
6710
6710
|
}
|
|
6711
6711
|
|
|
6712
|
-
// src/utils/
|
|
6712
|
+
// src/utils/root-package.ts
|
|
6713
6713
|
import fs2 from "fs-extra";
|
|
6714
6714
|
import path2 from "path";
|
|
6715
|
+
import chalk2 from "chalk";
|
|
6716
|
+
import { execa as execa2 } from "execa";
|
|
6717
|
+
function createRootPackageJsonContent(projectName, cliVersion) {
|
|
6718
|
+
return {
|
|
6719
|
+
name: projectName,
|
|
6720
|
+
private: true,
|
|
6721
|
+
description: "Baseboards project - AI-powered creative toolkit",
|
|
6722
|
+
scripts: {
|
|
6723
|
+
dev: "baseboards dev",
|
|
6724
|
+
up: "baseboards up",
|
|
6725
|
+
down: "baseboards down",
|
|
6726
|
+
logs: "baseboards logs -f",
|
|
6727
|
+
status: "baseboards status",
|
|
6728
|
+
clean: "baseboards clean"
|
|
6729
|
+
},
|
|
6730
|
+
devDependencies: {
|
|
6731
|
+
"@weirdfingers/baseboards": `^${cliVersion}`
|
|
6732
|
+
}
|
|
6733
|
+
};
|
|
6734
|
+
}
|
|
6735
|
+
async function generateRootPackageJson(projectDir, projectName, cliVersion) {
|
|
6736
|
+
const packageJsonPath = path2.join(projectDir, "package.json");
|
|
6737
|
+
if (await fs2.pathExists(packageJsonPath)) {
|
|
6738
|
+
return;
|
|
6739
|
+
}
|
|
6740
|
+
const content = createRootPackageJsonContent(projectName, cliVersion);
|
|
6741
|
+
await fs2.writeJson(packageJsonPath, content, { spaces: 2 });
|
|
6742
|
+
}
|
|
6743
|
+
async function installRootDependencies(projectDir, packageManager) {
|
|
6744
|
+
const packageJsonPath = path2.join(projectDir, "package.json");
|
|
6745
|
+
if (!await fs2.pathExists(packageJsonPath)) {
|
|
6746
|
+
console.log(
|
|
6747
|
+
chalk2.yellow(
|
|
6748
|
+
"\n\u26A0\uFE0F No package.json found at project root, skipping dependency installation"
|
|
6749
|
+
)
|
|
6750
|
+
);
|
|
6751
|
+
return;
|
|
6752
|
+
}
|
|
6753
|
+
console.log(
|
|
6754
|
+
chalk2.cyan(
|
|
6755
|
+
`
|
|
6756
|
+
\u{1F4E6} Installing project dependencies with ${packageManager}...`
|
|
6757
|
+
)
|
|
6758
|
+
);
|
|
6759
|
+
try {
|
|
6760
|
+
await execa2(packageManager, ["install"], {
|
|
6761
|
+
cwd: projectDir,
|
|
6762
|
+
stdio: "inherit"
|
|
6763
|
+
});
|
|
6764
|
+
console.log(chalk2.green("\u2705 Project dependencies installed successfully"));
|
|
6765
|
+
console.log(
|
|
6766
|
+
chalk2.gray(" You can now use: ") + chalk2.cyan("npm run dev") + chalk2.gray(", ") + chalk2.cyan("npm run up") + chalk2.gray(", etc.")
|
|
6767
|
+
);
|
|
6768
|
+
} catch (error) {
|
|
6769
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6770
|
+
console.error(
|
|
6771
|
+
chalk2.red(`
|
|
6772
|
+
\u274C Failed to install dependencies: ${errorMessage}`)
|
|
6773
|
+
);
|
|
6774
|
+
console.log(chalk2.yellow("\nTroubleshooting:"));
|
|
6775
|
+
console.log(
|
|
6776
|
+
chalk2.gray(" \u2022 Check that package.json is valid:"),
|
|
6777
|
+
chalk2.cyan(`${projectDir}/package.json`)
|
|
6778
|
+
);
|
|
6779
|
+
console.log(
|
|
6780
|
+
chalk2.gray(` \u2022 Ensure ${packageManager} is installed:`),
|
|
6781
|
+
chalk2.cyan(`${packageManager} --version`)
|
|
6782
|
+
);
|
|
6783
|
+
console.log(
|
|
6784
|
+
chalk2.gray(" \u2022 Try running the install manually:"),
|
|
6785
|
+
chalk2.cyan(`cd ${projectDir} && ${packageManager} install`)
|
|
6786
|
+
);
|
|
6787
|
+
throw error;
|
|
6788
|
+
}
|
|
6789
|
+
}
|
|
6790
|
+
|
|
6791
|
+
// src/utils/monorepo-detection.ts
|
|
6792
|
+
import fs3 from "fs-extra";
|
|
6793
|
+
import path3 from "path";
|
|
6715
6794
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6716
6795
|
async function detectMonorepoRoot() {
|
|
6717
6796
|
const currentFile = fileURLToPath2(import.meta.url);
|
|
6718
|
-
const cliPackageDir =
|
|
6797
|
+
const cliPackageDir = path3.resolve(path3.dirname(currentFile), "../..");
|
|
6719
6798
|
let currentDir = cliPackageDir;
|
|
6720
6799
|
const maxDepth = 5;
|
|
6721
6800
|
for (let depth = 0; depth < maxDepth; depth++) {
|
|
6722
6801
|
try {
|
|
6723
|
-
const workspaceFile =
|
|
6724
|
-
if (!await
|
|
6725
|
-
const parentDir =
|
|
6802
|
+
const workspaceFile = path3.join(currentDir, "pnpm-workspace.yaml");
|
|
6803
|
+
if (!await fs3.pathExists(workspaceFile)) {
|
|
6804
|
+
const parentDir = path3.dirname(currentDir);
|
|
6726
6805
|
if (parentDir === currentDir) {
|
|
6727
6806
|
break;
|
|
6728
6807
|
}
|
|
6729
6808
|
currentDir = parentDir;
|
|
6730
6809
|
continue;
|
|
6731
6810
|
}
|
|
6732
|
-
const frontendPackageJson =
|
|
6811
|
+
const frontendPackageJson = path3.join(
|
|
6733
6812
|
currentDir,
|
|
6734
6813
|
"packages/frontend/package.json"
|
|
6735
6814
|
);
|
|
6736
|
-
if (!await
|
|
6737
|
-
const parentDir =
|
|
6815
|
+
if (!await fs3.pathExists(frontendPackageJson)) {
|
|
6816
|
+
const parentDir = path3.dirname(currentDir);
|
|
6738
6817
|
if (parentDir === currentDir) {
|
|
6739
6818
|
break;
|
|
6740
6819
|
}
|
|
6741
6820
|
currentDir = parentDir;
|
|
6742
6821
|
continue;
|
|
6743
6822
|
}
|
|
6744
|
-
const packageData = await
|
|
6823
|
+
const packageData = await fs3.readJSON(frontendPackageJson);
|
|
6745
6824
|
if (packageData.name !== "@weirdfingers/boards") {
|
|
6746
|
-
const parentDir =
|
|
6825
|
+
const parentDir = path3.dirname(currentDir);
|
|
6747
6826
|
if (parentDir === currentDir) {
|
|
6748
6827
|
break;
|
|
6749
6828
|
}
|
|
@@ -6752,7 +6831,7 @@ async function detectMonorepoRoot() {
|
|
|
6752
6831
|
}
|
|
6753
6832
|
return currentDir;
|
|
6754
6833
|
} catch (error) {
|
|
6755
|
-
const parentDir =
|
|
6834
|
+
const parentDir = path3.dirname(currentDir);
|
|
6756
6835
|
if (parentDir === currentDir) {
|
|
6757
6836
|
break;
|
|
6758
6837
|
}
|
|
@@ -6764,8 +6843,8 @@ async function detectMonorepoRoot() {
|
|
|
6764
6843
|
}
|
|
6765
6844
|
|
|
6766
6845
|
// src/utils/package-copy.ts
|
|
6767
|
-
import
|
|
6768
|
-
import
|
|
6846
|
+
import fs4 from "fs-extra";
|
|
6847
|
+
import path4 from "path";
|
|
6769
6848
|
function shouldCopyFile(filePath) {
|
|
6770
6849
|
const excluded = [
|
|
6771
6850
|
"node_modules",
|
|
@@ -6778,23 +6857,23 @@ function shouldCopyFile(filePath) {
|
|
|
6778
6857
|
return !excluded.some((ex) => filePath.includes(ex));
|
|
6779
6858
|
}
|
|
6780
6859
|
async function copyFrontendPackage(monorepoRoot, targetDir) {
|
|
6781
|
-
const sourceFrontendDir =
|
|
6782
|
-
if (!await
|
|
6860
|
+
const sourceFrontendDir = path4.join(monorepoRoot, "packages/frontend");
|
|
6861
|
+
if (!await fs4.pathExists(sourceFrontendDir)) {
|
|
6783
6862
|
throw new Error(
|
|
6784
6863
|
`Frontend package not found at: ${sourceFrontendDir}
|
|
6785
6864
|
The monorepo structure may be corrupted.`
|
|
6786
6865
|
);
|
|
6787
6866
|
}
|
|
6788
|
-
await
|
|
6867
|
+
await fs4.ensureDir(targetDir);
|
|
6789
6868
|
try {
|
|
6790
|
-
await
|
|
6869
|
+
await fs4.copy(sourceFrontendDir, targetDir, {
|
|
6791
6870
|
filter: (src) => shouldCopyFile(src),
|
|
6792
6871
|
overwrite: true,
|
|
6793
6872
|
errorOnExist: false
|
|
6794
6873
|
});
|
|
6795
6874
|
} catch (error) {
|
|
6796
6875
|
try {
|
|
6797
|
-
await
|
|
6876
|
+
await fs4.remove(targetDir);
|
|
6798
6877
|
} catch {
|
|
6799
6878
|
}
|
|
6800
6879
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -6814,15 +6893,15 @@ Error: ${errorMessage}`
|
|
|
6814
6893
|
}
|
|
6815
6894
|
}
|
|
6816
6895
|
async function updatePackageJsonForDevPackages(webDir) {
|
|
6817
|
-
const packageJsonPath =
|
|
6818
|
-
if (!await
|
|
6896
|
+
const packageJsonPath = path4.join(webDir, "package.json");
|
|
6897
|
+
if (!await fs4.pathExists(packageJsonPath)) {
|
|
6819
6898
|
throw new Error(
|
|
6820
6899
|
`package.json not found at: ${packageJsonPath}
|
|
6821
6900
|
The web directory may not be properly scaffolded.`
|
|
6822
6901
|
);
|
|
6823
6902
|
}
|
|
6824
6903
|
try {
|
|
6825
|
-
const packageData = await
|
|
6904
|
+
const packageData = await fs4.readJSON(packageJsonPath);
|
|
6826
6905
|
if (packageData.dependencies && packageData.dependencies["@weirdfingers/boards"]) {
|
|
6827
6906
|
packageData.dependencies["@weirdfingers/boards"] = "file:../frontend";
|
|
6828
6907
|
} else if (packageData.devDependencies && packageData.devDependencies["@weirdfingers/boards"]) {
|
|
@@ -6833,7 +6912,7 @@ The web directory may not be properly scaffolded.`
|
|
|
6833
6912
|
The package may not be installed or the package.json structure is unexpected.`
|
|
6834
6913
|
);
|
|
6835
6914
|
}
|
|
6836
|
-
await
|
|
6915
|
+
await fs4.writeJSON(packageJsonPath, packageData, { spaces: 2 });
|
|
6837
6916
|
} catch (error) {
|
|
6838
6917
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6839
6918
|
if (errorMessage.includes("EACCES") || errorMessage.includes("EPERM")) {
|
|
@@ -6861,8 +6940,8 @@ Error: ${errorMessage}`
|
|
|
6861
6940
|
}
|
|
6862
6941
|
|
|
6863
6942
|
// src/utils/template-downloader.ts
|
|
6864
|
-
import
|
|
6865
|
-
import
|
|
6943
|
+
import fs5 from "fs-extra";
|
|
6944
|
+
import path5 from "path";
|
|
6866
6945
|
import { createHash } from "crypto";
|
|
6867
6946
|
import { extract } from "tar";
|
|
6868
6947
|
import { tmpdir, homedir } from "os";
|
|
@@ -7013,12 +7092,12 @@ function handleFetchError(error, context) {
|
|
|
7013
7092
|
throw error;
|
|
7014
7093
|
}
|
|
7015
7094
|
function getCacheDir() {
|
|
7016
|
-
return
|
|
7095
|
+
return path5.join(homedir(), ".baseboards", "templates");
|
|
7017
7096
|
}
|
|
7018
7097
|
async function ensureCacheDir() {
|
|
7019
7098
|
const cacheDir = getCacheDir();
|
|
7020
7099
|
try {
|
|
7021
|
-
await
|
|
7100
|
+
await fs5.ensureDir(cacheDir);
|
|
7022
7101
|
} catch (error) {
|
|
7023
7102
|
if (error.code === "EACCES" || error.code === "EPERM") {
|
|
7024
7103
|
throw new PermissionError(
|
|
@@ -7087,15 +7166,15 @@ async function fetchTemplateManifest(version) {
|
|
|
7087
7166
|
}
|
|
7088
7167
|
await ensureCacheDir();
|
|
7089
7168
|
const cacheDir = getCacheDir();
|
|
7090
|
-
const cachedManifestPath =
|
|
7091
|
-
if (await
|
|
7169
|
+
const cachedManifestPath = path5.join(cacheDir, `manifest-v${actualVersion}.json`);
|
|
7170
|
+
if (await fs5.pathExists(cachedManifestPath)) {
|
|
7092
7171
|
try {
|
|
7093
|
-
const cachedManifest = await
|
|
7172
|
+
const cachedManifest = await fs5.readJson(cachedManifestPath);
|
|
7094
7173
|
if (cachedManifest.version && Array.isArray(cachedManifest.templates)) {
|
|
7095
7174
|
return cachedManifest;
|
|
7096
7175
|
}
|
|
7097
7176
|
} catch (error) {
|
|
7098
|
-
await
|
|
7177
|
+
await fs5.remove(cachedManifestPath);
|
|
7099
7178
|
}
|
|
7100
7179
|
}
|
|
7101
7180
|
const maxRetries = 3;
|
|
@@ -7142,7 +7221,7 @@ async function fetchTemplateManifest(version) {
|
|
|
7142
7221
|
throw new Error("Invalid manifest structure");
|
|
7143
7222
|
}
|
|
7144
7223
|
try {
|
|
7145
|
-
await
|
|
7224
|
+
await fs5.writeJson(cachedManifestPath, manifest, { spaces: 2 });
|
|
7146
7225
|
} catch (error) {
|
|
7147
7226
|
if (error.code === "EACCES" || error.code === "EPERM") {
|
|
7148
7227
|
} else if (error.code === "ENOSPC") {
|
|
@@ -7191,7 +7270,7 @@ async function verifyChecksum(filePath, expectedChecksum) {
|
|
|
7191
7270
|
}
|
|
7192
7271
|
const expectedHash = expectedChecksum.replace("sha256:", "");
|
|
7193
7272
|
const hash = createHash("sha256");
|
|
7194
|
-
const fileStream =
|
|
7273
|
+
const fileStream = fs5.createReadStream(filePath);
|
|
7195
7274
|
return new Promise((resolve, reject) => {
|
|
7196
7275
|
fileStream.on("data", (chunk) => {
|
|
7197
7276
|
hash.update(chunk);
|
|
@@ -7235,13 +7314,13 @@ async function downloadTemplate(name, version, targetDir) {
|
|
|
7235
7314
|
}
|
|
7236
7315
|
await ensureCacheDir();
|
|
7237
7316
|
const cacheDir = getCacheDir();
|
|
7238
|
-
const cachedFilePath =
|
|
7317
|
+
const cachedFilePath = path5.join(
|
|
7239
7318
|
cacheDir,
|
|
7240
7319
|
`template-${name}-v${manifest.version}.tar.gz`
|
|
7241
7320
|
);
|
|
7242
7321
|
let sourceFilePath;
|
|
7243
7322
|
let cacheHit = false;
|
|
7244
|
-
if (await
|
|
7323
|
+
if (await fs5.pathExists(cachedFilePath)) {
|
|
7245
7324
|
try {
|
|
7246
7325
|
await verifyChecksum(cachedFilePath, template.checksum);
|
|
7247
7326
|
sourceFilePath = cachedFilePath;
|
|
@@ -7252,7 +7331,7 @@ async function downloadTemplate(name, version, targetDir) {
|
|
|
7252
7331
|
console.log(`Using cached template ${name}...`);
|
|
7253
7332
|
}
|
|
7254
7333
|
} catch (error) {
|
|
7255
|
-
await
|
|
7334
|
+
await fs5.remove(cachedFilePath);
|
|
7256
7335
|
if (isInteractive) {
|
|
7257
7336
|
console.log(`
|
|
7258
7337
|
Downloading template ${name}...`);
|
|
@@ -7283,7 +7362,7 @@ Downloading template ${name}...`);
|
|
|
7283
7362
|
);
|
|
7284
7363
|
}
|
|
7285
7364
|
try {
|
|
7286
|
-
await
|
|
7365
|
+
await fs5.ensureDir(targetDir);
|
|
7287
7366
|
} catch (error) {
|
|
7288
7367
|
if (error.code === "EACCES" || error.code === "EPERM") {
|
|
7289
7368
|
throw new PermissionError(
|
|
@@ -7307,9 +7386,9 @@ Downloading template ${name}...`);
|
|
|
7307
7386
|
console.log("Extracting template...");
|
|
7308
7387
|
}
|
|
7309
7388
|
const tempDir = tmpdir();
|
|
7310
|
-
extractTempDir =
|
|
7389
|
+
extractTempDir = path5.join(tempDir, `extract-${name}-${Date.now()}`);
|
|
7311
7390
|
try {
|
|
7312
|
-
await
|
|
7391
|
+
await fs5.ensureDir(extractTempDir);
|
|
7313
7392
|
} catch (error) {
|
|
7314
7393
|
if (error.code === "ENOSPC") {
|
|
7315
7394
|
throw new DiskSpaceError(
|
|
@@ -7333,11 +7412,11 @@ Downloading template ${name}...`);
|
|
|
7333
7412
|
);
|
|
7334
7413
|
}
|
|
7335
7414
|
try {
|
|
7336
|
-
const files = await
|
|
7415
|
+
const files = await fs5.readdir(extractTempDir);
|
|
7337
7416
|
for (const file of files) {
|
|
7338
|
-
const srcPath =
|
|
7339
|
-
const destPath =
|
|
7340
|
-
await
|
|
7417
|
+
const srcPath = path5.join(extractTempDir, file);
|
|
7418
|
+
const destPath = path5.join(targetDir, file);
|
|
7419
|
+
await fs5.move(srcPath, destPath, { overwrite: true });
|
|
7341
7420
|
}
|
|
7342
7421
|
} catch (error) {
|
|
7343
7422
|
if (error.code === "EACCES" || error.code === "EPERM") {
|
|
@@ -7356,7 +7435,7 @@ Downloading template ${name}...`);
|
|
|
7356
7435
|
}
|
|
7357
7436
|
throw error;
|
|
7358
7437
|
}
|
|
7359
|
-
await
|
|
7438
|
+
await fs5.remove(extractTempDir);
|
|
7360
7439
|
extractTempDir = null;
|
|
7361
7440
|
if (spinner && isInteractive) {
|
|
7362
7441
|
spinner.succeed("Template ready");
|
|
@@ -7368,11 +7447,11 @@ Downloading template ${name}...`);
|
|
|
7368
7447
|
spinner.fail("Download failed");
|
|
7369
7448
|
}
|
|
7370
7449
|
try {
|
|
7371
|
-
if (tempFilePath && await
|
|
7372
|
-
await
|
|
7450
|
+
if (tempFilePath && await fs5.pathExists(tempFilePath)) {
|
|
7451
|
+
await fs5.remove(tempFilePath);
|
|
7373
7452
|
}
|
|
7374
|
-
if (extractTempDir && await
|
|
7375
|
-
await
|
|
7453
|
+
if (extractTempDir && await fs5.pathExists(extractTempDir)) {
|
|
7454
|
+
await fs5.remove(extractTempDir);
|
|
7376
7455
|
}
|
|
7377
7456
|
} catch (cleanupError) {
|
|
7378
7457
|
}
|
|
@@ -7384,7 +7463,7 @@ async function downloadAndCache(version, template, cachedFilePath, spinner = nul
|
|
|
7384
7463
|
const maxChecksumRetries = 2;
|
|
7385
7464
|
for (let checksumAttempt = 1; checksumAttempt <= maxChecksumRetries; checksumAttempt++) {
|
|
7386
7465
|
const tempDir = tmpdir();
|
|
7387
|
-
const tempFilePath =
|
|
7466
|
+
const tempFilePath = path5.join(tempDir, `${template.file}.tmp-${Date.now()}`);
|
|
7388
7467
|
try {
|
|
7389
7468
|
const maxDownloadRetries = 3;
|
|
7390
7469
|
let downloadedBytes = 0;
|
|
@@ -7465,7 +7544,7 @@ async function downloadAndCache(version, template, cachedFilePath, spinner = nul
|
|
|
7465
7544
|
let lastTime = Date.now();
|
|
7466
7545
|
let lastLoaded = 0;
|
|
7467
7546
|
const reader = response.body.getReader();
|
|
7468
|
-
const fileStream =
|
|
7547
|
+
const fileStream = fs5.createWriteStream(tempFilePath);
|
|
7469
7548
|
try {
|
|
7470
7549
|
while (true) {
|
|
7471
7550
|
const { done, value } = await reader.read();
|
|
@@ -7510,7 +7589,7 @@ async function downloadAndCache(version, template, cachedFilePath, spinner = nul
|
|
|
7510
7589
|
}
|
|
7511
7590
|
await verifyChecksum(tempFilePath, template.checksum);
|
|
7512
7591
|
try {
|
|
7513
|
-
await
|
|
7592
|
+
await fs5.move(tempFilePath, cachedFilePath, { overwrite: true });
|
|
7514
7593
|
} catch (error) {
|
|
7515
7594
|
if (error.code === "ENOSPC") {
|
|
7516
7595
|
throw new DiskSpaceError(
|
|
@@ -7532,8 +7611,8 @@ async function downloadAndCache(version, template, cachedFilePath, spinner = nul
|
|
|
7532
7611
|
} catch (error) {
|
|
7533
7612
|
if (error instanceof ChecksumError) {
|
|
7534
7613
|
if (checksumAttempt < maxChecksumRetries) {
|
|
7535
|
-
if (await
|
|
7536
|
-
await
|
|
7614
|
+
if (await fs5.pathExists(tempFilePath)) {
|
|
7615
|
+
await fs5.remove(tempFilePath);
|
|
7537
7616
|
}
|
|
7538
7617
|
if (spinner) {
|
|
7539
7618
|
spinner.text = `Checksum verification failed. Retrying download (attempt ${checksumAttempt + 1}/${maxChecksumRetries})...`;
|
|
@@ -7556,8 +7635,8 @@ async function downloadAndCache(version, template, cachedFilePath, spinner = nul
|
|
|
7556
7635
|
}
|
|
7557
7636
|
} catch (error) {
|
|
7558
7637
|
try {
|
|
7559
|
-
if (await
|
|
7560
|
-
await
|
|
7638
|
+
if (await fs5.pathExists(tempFilePath)) {
|
|
7639
|
+
await fs5.remove(tempFilePath);
|
|
7561
7640
|
}
|
|
7562
7641
|
} catch (cleanupError) {
|
|
7563
7642
|
}
|
|
@@ -7574,12 +7653,12 @@ async function clearCache() {
|
|
|
7574
7653
|
const cacheDir = getCacheDir();
|
|
7575
7654
|
await ensureCacheDir();
|
|
7576
7655
|
try {
|
|
7577
|
-
const files = await
|
|
7656
|
+
const files = await fs5.readdir(cacheDir);
|
|
7578
7657
|
for (const file of files) {
|
|
7579
|
-
const filePath =
|
|
7580
|
-
const stat = await
|
|
7658
|
+
const filePath = path5.join(cacheDir, file);
|
|
7659
|
+
const stat = await fs5.stat(filePath);
|
|
7581
7660
|
if (stat.isFile()) {
|
|
7582
|
-
await
|
|
7661
|
+
await fs5.remove(filePath);
|
|
7583
7662
|
}
|
|
7584
7663
|
}
|
|
7585
7664
|
} catch (error) {
|
|
@@ -7601,34 +7680,34 @@ async function validateTemplate(templateName, version) {
|
|
|
7601
7680
|
}
|
|
7602
7681
|
}
|
|
7603
7682
|
async function installFrontendDependencies(ctx) {
|
|
7604
|
-
const webDir =
|
|
7605
|
-
const packageJsonPath =
|
|
7606
|
-
if (!
|
|
7607
|
-
console.log(
|
|
7683
|
+
const webDir = path6.join(ctx.dir, "web");
|
|
7684
|
+
const packageJsonPath = path6.join(webDir, "package.json");
|
|
7685
|
+
if (!fs6.existsSync(packageJsonPath)) {
|
|
7686
|
+
console.log(chalk3.yellow("\n\u26A0\uFE0F No package.json found in web directory, skipping dependency installation"));
|
|
7608
7687
|
return;
|
|
7609
7688
|
}
|
|
7610
7689
|
if (!ctx.packageManager) {
|
|
7611
7690
|
ctx.packageManager = await promptPackageManager();
|
|
7612
7691
|
}
|
|
7613
7692
|
const packageManager = ctx.packageManager;
|
|
7614
|
-
console.log(
|
|
7693
|
+
console.log(chalk3.cyan(`
|
|
7615
7694
|
\u{1F4E6} Installing frontend dependencies with ${packageManager}...`));
|
|
7616
7695
|
const installCmd = "install";
|
|
7617
7696
|
try {
|
|
7618
|
-
await
|
|
7697
|
+
await execa3(packageManager, [installCmd], {
|
|
7619
7698
|
cwd: webDir,
|
|
7620
7699
|
stdio: "inherit"
|
|
7621
7700
|
// Show install output to user
|
|
7622
7701
|
});
|
|
7623
|
-
console.log(
|
|
7702
|
+
console.log(chalk3.green("\u2705 Dependencies installed successfully\n"));
|
|
7624
7703
|
} catch (error) {
|
|
7625
7704
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
7626
|
-
console.error(
|
|
7705
|
+
console.error(chalk3.red(`
|
|
7627
7706
|
\u274C Failed to install dependencies: ${errorMessage}`));
|
|
7628
|
-
console.log(
|
|
7629
|
-
console.log(
|
|
7630
|
-
console.log(
|
|
7631
|
-
console.log(
|
|
7707
|
+
console.log(chalk3.yellow("\nTroubleshooting:"));
|
|
7708
|
+
console.log(chalk3.gray(" \u2022 Check that package.json is valid:"), chalk3.cyan(`${webDir}/package.json`));
|
|
7709
|
+
console.log(chalk3.gray(` \u2022 Ensure ${packageManager} is installed:`), chalk3.cyan(`${packageManager} --version`));
|
|
7710
|
+
console.log(chalk3.gray(" \u2022 Try running the install manually:"), chalk3.cyan(`cd ${webDir} && ${packageManager} install`));
|
|
7632
7711
|
throw error;
|
|
7633
7712
|
}
|
|
7634
7713
|
}
|
|
@@ -7659,12 +7738,12 @@ async function promptTemplateSelection(version) {
|
|
|
7659
7738
|
}
|
|
7660
7739
|
}
|
|
7661
7740
|
async function up(directory, options) {
|
|
7662
|
-
console.log(
|
|
7741
|
+
console.log(chalk3.blue.bold("\n\u{1F3A8} Baseboards CLI\n"));
|
|
7663
7742
|
const spinner = ora2("Checking prerequisites...").start();
|
|
7664
7743
|
await assertPrerequisites();
|
|
7665
7744
|
spinner.succeed("Prerequisites OK");
|
|
7666
|
-
const dir =
|
|
7667
|
-
const name =
|
|
7745
|
+
const dir = path6.resolve(process.cwd(), directory);
|
|
7746
|
+
const name = path6.basename(dir);
|
|
7668
7747
|
const version = getCliVersion();
|
|
7669
7748
|
let customPorts = {};
|
|
7670
7749
|
if (options.ports) {
|
|
@@ -7720,17 +7799,17 @@ async function up(directory, options) {
|
|
|
7720
7799
|
await cleanupDockerVolumes(ctx);
|
|
7721
7800
|
} else if (!ctx.isScaffolded) {
|
|
7722
7801
|
console.log(
|
|
7723
|
-
|
|
7802
|
+
chalk3.yellow(
|
|
7724
7803
|
"\n\u26A0\uFE0F Existing Docker volumes detected from a previous installation"
|
|
7725
7804
|
)
|
|
7726
7805
|
);
|
|
7727
7806
|
console.log(
|
|
7728
|
-
|
|
7807
|
+
chalk3.gray(
|
|
7729
7808
|
" To avoid password mismatch errors, you can start fresh or cancel."
|
|
7730
7809
|
)
|
|
7731
7810
|
);
|
|
7732
7811
|
console.log(
|
|
7733
|
-
|
|
7812
|
+
chalk3.gray(
|
|
7734
7813
|
" Starting fresh will delete ALL existing data (boards, generated images, users)."
|
|
7735
7814
|
)
|
|
7736
7815
|
);
|
|
@@ -7741,22 +7820,22 @@ async function up(directory, options) {
|
|
|
7741
7820
|
initial: true
|
|
7742
7821
|
});
|
|
7743
7822
|
if (response.cleanVolumes === void 0) {
|
|
7744
|
-
console.log(
|
|
7823
|
+
console.log(chalk3.yellow("\n\u26A0\uFE0F Cancelled by user"));
|
|
7745
7824
|
process.exit(0);
|
|
7746
7825
|
}
|
|
7747
7826
|
if (response.cleanVolumes) {
|
|
7748
7827
|
await cleanupDockerVolumes(ctx);
|
|
7749
7828
|
} else {
|
|
7750
7829
|
console.log(
|
|
7751
|
-
|
|
7830
|
+
chalk3.yellow(
|
|
7752
7831
|
"\n\u26A0\uFE0F Proceeding without cleaning volumes. If you encounter password errors:"
|
|
7753
7832
|
)
|
|
7754
7833
|
);
|
|
7755
7834
|
console.log(
|
|
7756
|
-
|
|
7835
|
+
chalk3.cyan(" baseboards up --fresh") + chalk3.gray(" (start fresh)")
|
|
7757
7836
|
);
|
|
7758
7837
|
console.log(
|
|
7759
|
-
|
|
7838
|
+
chalk3.cyan(" baseboards down --volumes && baseboards up") + chalk3.gray(" (manual cleanup)")
|
|
7760
7839
|
);
|
|
7761
7840
|
}
|
|
7762
7841
|
}
|
|
@@ -7764,24 +7843,24 @@ async function up(directory, options) {
|
|
|
7764
7843
|
}
|
|
7765
7844
|
if (!ctx.isScaffolded) {
|
|
7766
7845
|
console.log(
|
|
7767
|
-
|
|
7768
|
-
\u{1F4E6} Scaffolding new project: ${
|
|
7846
|
+
chalk3.cyan(`
|
|
7847
|
+
\u{1F4E6} Scaffolding new project: ${chalk3.bold(name)}`)
|
|
7769
7848
|
);
|
|
7770
7849
|
await scaffoldProject(ctx);
|
|
7771
7850
|
} else {
|
|
7772
7851
|
console.log(
|
|
7773
|
-
|
|
7774
|
-
\u2705 Project already scaffolded: ${
|
|
7852
|
+
chalk3.green(`
|
|
7853
|
+
\u2705 Project already scaffolded: ${chalk3.bold(name)}`)
|
|
7775
7854
|
);
|
|
7776
7855
|
}
|
|
7777
7856
|
if (ctx.devPackages && ctx.monorepoRoot) {
|
|
7778
7857
|
const spinner2 = ora2("Copying @weirdfingers/boards source from monorepo...").start();
|
|
7779
7858
|
try {
|
|
7780
|
-
const targetFrontend =
|
|
7859
|
+
const targetFrontend = path6.join(ctx.dir, "frontend");
|
|
7781
7860
|
await copyFrontendPackage(ctx.monorepoRoot, targetFrontend);
|
|
7782
7861
|
spinner2.succeed("Package source copied");
|
|
7783
7862
|
spinner2.start("Linking local package...");
|
|
7784
|
-
const webDir =
|
|
7863
|
+
const webDir = path6.join(ctx.dir, "web");
|
|
7785
7864
|
await updatePackageJsonForDevPackages(webDir);
|
|
7786
7865
|
spinner2.succeed("Local package linked successfully");
|
|
7787
7866
|
} catch (error) {
|
|
@@ -7799,28 +7878,34 @@ async function up(directory, options) {
|
|
|
7799
7878
|
if (isFreshScaffold) {
|
|
7800
7879
|
await promptForApiKeys(ctx);
|
|
7801
7880
|
}
|
|
7802
|
-
|
|
7881
|
+
if (isFreshScaffold) {
|
|
7882
|
+
if (!ctx.packageManager) {
|
|
7883
|
+
ctx.packageManager = await promptPackageManager();
|
|
7884
|
+
}
|
|
7885
|
+
await installRootDependencies(ctx.dir, ctx.packageManager);
|
|
7886
|
+
}
|
|
7887
|
+
const apiEnvPath = path6.join(ctx.dir, "api/.env");
|
|
7803
7888
|
const missingKeys = detectMissingProviderKeys(apiEnvPath);
|
|
7804
7889
|
if (missingKeys.length > 0) {
|
|
7805
|
-
console.log(
|
|
7806
|
-
console.log(
|
|
7890
|
+
console.log(chalk3.yellow("\n\u26A0\uFE0F Provider API keys not configured!"));
|
|
7891
|
+
console.log(chalk3.gray(" Add at least one API key to api/.env:"));
|
|
7807
7892
|
console.log(
|
|
7808
|
-
|
|
7893
|
+
chalk3.cyan(" \u2022 REPLICATE_API_TOKEN") + chalk3.gray(" - https://replicate.com/account/api-tokens")
|
|
7809
7894
|
);
|
|
7810
7895
|
console.log(
|
|
7811
|
-
|
|
7896
|
+
chalk3.cyan(" \u2022 FAL_KEY") + chalk3.gray(" - https://fal.ai/dashboard/keys")
|
|
7812
7897
|
);
|
|
7813
7898
|
console.log(
|
|
7814
|
-
|
|
7899
|
+
chalk3.cyan(" \u2022 KIE_API_KEY") + chalk3.gray(" - https://kie.ai/dashboard")
|
|
7815
7900
|
);
|
|
7816
7901
|
console.log(
|
|
7817
|
-
|
|
7902
|
+
chalk3.cyan(" \u2022 OPENAI_API_KEY") + chalk3.gray(" - https://platform.openai.com/api-keys")
|
|
7818
7903
|
);
|
|
7819
7904
|
console.log(
|
|
7820
|
-
|
|
7905
|
+
chalk3.cyan(" \u2022 GOOGLE_API_KEY") + chalk3.gray(" - https://makersuite.google.com/app/apikey")
|
|
7821
7906
|
);
|
|
7822
7907
|
console.log(
|
|
7823
|
-
|
|
7908
|
+
chalk3.gray(
|
|
7824
7909
|
"\n The app will start, but image generation won't work without keys.\n"
|
|
7825
7910
|
)
|
|
7826
7911
|
);
|
|
@@ -7838,7 +7923,7 @@ async function up(directory, options) {
|
|
|
7838
7923
|
} catch (error) {
|
|
7839
7924
|
const maybeProcError = error;
|
|
7840
7925
|
if (maybeProcError.signal === "SIGINT" || maybeProcError.exitCode === 130) {
|
|
7841
|
-
console.log(
|
|
7926
|
+
console.log(chalk3.yellow("\n\n\u26A0\uFE0F Interrupted - services stopped"));
|
|
7842
7927
|
process.exit(0);
|
|
7843
7928
|
}
|
|
7844
7929
|
throw error;
|
|
@@ -7846,29 +7931,32 @@ async function up(directory, options) {
|
|
|
7846
7931
|
}
|
|
7847
7932
|
}
|
|
7848
7933
|
async function scaffoldProject(ctx) {
|
|
7849
|
-
|
|
7934
|
+
fs6.ensureDirSync(ctx.dir);
|
|
7850
7935
|
await downloadTemplate(ctx.template, ctx.version, ctx.dir);
|
|
7851
7936
|
const spinner = ora2("Creating data directories...").start();
|
|
7852
|
-
|
|
7937
|
+
fs6.ensureDirSync(path6.join(ctx.dir, "data/storage"));
|
|
7853
7938
|
spinner.succeed("Data directories created");
|
|
7854
|
-
|
|
7939
|
+
spinner.start("Generating project configuration...");
|
|
7940
|
+
await generateRootPackageJson(ctx.dir, ctx.name, ctx.version);
|
|
7941
|
+
spinner.succeed("Project configuration created");
|
|
7942
|
+
console.log(chalk3.green(" \u2728 Project scaffolded successfully!"));
|
|
7855
7943
|
}
|
|
7856
7944
|
async function ensureEnvFiles(ctx) {
|
|
7857
7945
|
const spinner = ora2("Configuring environment...").start();
|
|
7858
|
-
const webEnvPath =
|
|
7859
|
-
const webEnvExamplePath =
|
|
7860
|
-
if (!
|
|
7861
|
-
let webEnv =
|
|
7946
|
+
const webEnvPath = path6.join(ctx.dir, "web/.env");
|
|
7947
|
+
const webEnvExamplePath = path6.join(ctx.dir, "web/.env.example");
|
|
7948
|
+
if (!fs6.existsSync(webEnvPath) && fs6.existsSync(webEnvExamplePath)) {
|
|
7949
|
+
let webEnv = fs6.readFileSync(webEnvExamplePath, "utf-8");
|
|
7862
7950
|
webEnv = webEnv.replace(
|
|
7863
7951
|
"http://localhost:8800",
|
|
7864
7952
|
`http://localhost:${ctx.ports.api}`
|
|
7865
7953
|
);
|
|
7866
|
-
|
|
7954
|
+
fs6.writeFileSync(webEnvPath, webEnv);
|
|
7867
7955
|
}
|
|
7868
|
-
const apiEnvPath =
|
|
7869
|
-
const apiEnvExamplePath =
|
|
7870
|
-
if (!
|
|
7871
|
-
let apiEnv =
|
|
7956
|
+
const apiEnvPath = path6.join(ctx.dir, "api/.env");
|
|
7957
|
+
const apiEnvExamplePath = path6.join(ctx.dir, "api/.env.example");
|
|
7958
|
+
if (!fs6.existsSync(apiEnvPath) && fs6.existsSync(apiEnvExamplePath)) {
|
|
7959
|
+
let apiEnv = fs6.readFileSync(apiEnvExamplePath, "utf-8");
|
|
7872
7960
|
if (apiEnv.includes("BOARDS_JWT_SECRET=\n") || apiEnv.includes("BOARDS_JWT_SECRET=\r\n")) {
|
|
7873
7961
|
const jwtSecret = generateSecret(32);
|
|
7874
7962
|
apiEnv = apiEnv.replace(
|
|
@@ -7876,12 +7964,12 @@ async function ensureEnvFiles(ctx) {
|
|
|
7876
7964
|
`BOARDS_JWT_SECRET=${jwtSecret}`
|
|
7877
7965
|
);
|
|
7878
7966
|
}
|
|
7879
|
-
|
|
7967
|
+
fs6.writeFileSync(apiEnvPath, apiEnv);
|
|
7880
7968
|
}
|
|
7881
|
-
const dockerEnvPath =
|
|
7882
|
-
const dockerEnvExamplePath =
|
|
7883
|
-
if (!
|
|
7884
|
-
let dockerEnv =
|
|
7969
|
+
const dockerEnvPath = path6.join(ctx.dir, "docker/.env");
|
|
7970
|
+
const dockerEnvExamplePath = path6.join(ctx.dir, "docker/env.example");
|
|
7971
|
+
if (!fs6.existsSync(dockerEnvPath) && fs6.existsSync(dockerEnvExamplePath)) {
|
|
7972
|
+
let dockerEnv = fs6.readFileSync(dockerEnvExamplePath, "utf-8");
|
|
7885
7973
|
const dbPassword = generatePassword(24);
|
|
7886
7974
|
const dbPasswordEncoded = encodeURIComponent(dbPassword);
|
|
7887
7975
|
dockerEnv = dockerEnv.replace(
|
|
@@ -7895,18 +7983,19 @@ async function ensureEnvFiles(ctx) {
|
|
|
7895
7983
|
dockerEnv = dockerEnv.replace(/WEB_PORT=.*/g, `WEB_PORT=${ctx.ports.web}`);
|
|
7896
7984
|
dockerEnv = dockerEnv.replace(/API_PORT=.*/g, `API_PORT=${ctx.ports.api}`);
|
|
7897
7985
|
dockerEnv = dockerEnv.replace(/VERSION=.*/g, `VERSION=${ctx.version}`);
|
|
7986
|
+
dockerEnv = dockerEnv.replace(/BACKEND_VERSION=.*/g, `BACKEND_VERSION=${ctx.version}`);
|
|
7898
7987
|
dockerEnv = dockerEnv.replace(
|
|
7899
7988
|
/PROJECT_NAME=.*/g,
|
|
7900
7989
|
`PROJECT_NAME=${ctx.name}`
|
|
7901
7990
|
);
|
|
7902
|
-
|
|
7991
|
+
fs6.writeFileSync(dockerEnvPath, dockerEnv);
|
|
7903
7992
|
}
|
|
7904
7993
|
spinner.succeed("Environment configured");
|
|
7905
7994
|
}
|
|
7906
7995
|
async function promptForApiKeys(ctx) {
|
|
7907
|
-
console.log(
|
|
7908
|
-
console.log(
|
|
7909
|
-
console.log(
|
|
7996
|
+
console.log(chalk3.cyan("\n\u{1F511} API Key Configuration"));
|
|
7997
|
+
console.log(chalk3.gray("Add API keys to enable image generation providers"));
|
|
7998
|
+
console.log(chalk3.gray("Press Enter to skip any key\n"));
|
|
7910
7999
|
const response = await prompts2([
|
|
7911
8000
|
{
|
|
7912
8001
|
type: "password",
|
|
@@ -7947,8 +8036,8 @@ async function promptForApiKeys(ctx) {
|
|
|
7947
8036
|
apiKeys.OPENAI_API_KEY = response.OPENAI_API_KEY.trim();
|
|
7948
8037
|
}
|
|
7949
8038
|
if (Object.keys(apiKeys).length > 0) {
|
|
7950
|
-
const apiEnvPath =
|
|
7951
|
-
let apiEnv =
|
|
8039
|
+
const apiEnvPath = path6.join(ctx.dir, "api/.env");
|
|
8040
|
+
let apiEnv = fs6.readFileSync(apiEnvPath, "utf-8");
|
|
7952
8041
|
const jsonKeys = JSON.stringify(apiKeys);
|
|
7953
8042
|
if (apiEnv.includes("BOARDS_GENERATOR_API_KEYS=")) {
|
|
7954
8043
|
apiEnv = apiEnv.replace(
|
|
@@ -7964,14 +8053,14 @@ BOARDS_GENERATOR_API_KEYS=${jsonKeys}
|
|
|
7964
8053
|
`
|
|
7965
8054
|
);
|
|
7966
8055
|
}
|
|
7967
|
-
|
|
7968
|
-
console.log(
|
|
8056
|
+
fs6.writeFileSync(apiEnvPath, apiEnv);
|
|
8057
|
+
console.log(chalk3.green("\n\u2705 API keys saved to api/.env"));
|
|
7969
8058
|
console.log(
|
|
7970
|
-
|
|
8059
|
+
chalk3.gray(" You can edit this file anytime to add/update keys\n")
|
|
7971
8060
|
);
|
|
7972
8061
|
} else {
|
|
7973
|
-
console.log(
|
|
7974
|
-
console.log(
|
|
8062
|
+
console.log(chalk3.yellow("\n\u26A0\uFE0F No API keys provided"));
|
|
8063
|
+
console.log(chalk3.gray(" You can add them later by editing api/.env\n"));
|
|
7975
8064
|
}
|
|
7976
8065
|
}
|
|
7977
8066
|
function getComposeFiles(ctx) {
|
|
@@ -7993,8 +8082,8 @@ async function startDockerCompose(ctx) {
|
|
|
7993
8082
|
const spinner = ora2("Starting Docker Compose...").start();
|
|
7994
8083
|
const composeFiles = getComposeFiles(ctx);
|
|
7995
8084
|
for (const file of composeFiles) {
|
|
7996
|
-
const filePath =
|
|
7997
|
-
if (!
|
|
8085
|
+
const filePath = path6.join(ctx.dir, file);
|
|
8086
|
+
if (!fs6.existsSync(filePath)) {
|
|
7998
8087
|
spinner.fail(`Compose file not found: ${file}`);
|
|
7999
8088
|
throw new Error(`Compose file not found: ${file}`);
|
|
8000
8089
|
}
|
|
@@ -8007,7 +8096,7 @@ async function startDockerCompose(ctx) {
|
|
|
8007
8096
|
"--remove-orphans"
|
|
8008
8097
|
];
|
|
8009
8098
|
try {
|
|
8010
|
-
await
|
|
8099
|
+
await execa3("docker", composeArgs, {
|
|
8011
8100
|
cwd: ctx.dir,
|
|
8012
8101
|
stdio: "inherit"
|
|
8013
8102
|
});
|
|
@@ -8019,11 +8108,11 @@ async function startDockerCompose(ctx) {
|
|
|
8019
8108
|
}
|
|
8020
8109
|
async function attachToLogs(ctx) {
|
|
8021
8110
|
console.log(
|
|
8022
|
-
|
|
8111
|
+
chalk3.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")
|
|
8023
8112
|
);
|
|
8024
|
-
console.log(
|
|
8113
|
+
console.log(chalk3.gray("Streaming logs... (Press Ctrl+C to stop)\n"));
|
|
8025
8114
|
const composeArgs = [...getComposeBaseArgs(ctx), "logs", "-f"];
|
|
8026
|
-
await
|
|
8115
|
+
await execa3("docker", composeArgs, {
|
|
8027
8116
|
cwd: ctx.dir,
|
|
8028
8117
|
stdio: "inherit"
|
|
8029
8118
|
});
|
|
@@ -8037,7 +8126,7 @@ async function waitForHealthy(ctx) {
|
|
|
8037
8126
|
const maxWaitMs = 12e4;
|
|
8038
8127
|
const checkHealth = async () => {
|
|
8039
8128
|
try {
|
|
8040
|
-
const { stdout } = await
|
|
8129
|
+
const { stdout } = await execa3(
|
|
8041
8130
|
"docker",
|
|
8042
8131
|
[...getComposeBaseArgs(ctx), "ps", "--format", "json"],
|
|
8043
8132
|
{
|
|
@@ -8067,21 +8156,21 @@ async function waitForHealthy(ctx) {
|
|
|
8067
8156
|
} else {
|
|
8068
8157
|
spinner.warn("Services taking longer than expected...");
|
|
8069
8158
|
console.log(
|
|
8070
|
-
|
|
8159
|
+
chalk3.yellow(
|
|
8071
8160
|
"\n\u26A0\uFE0F Health check timeout. Services may still be starting."
|
|
8072
8161
|
)
|
|
8073
8162
|
);
|
|
8074
8163
|
console.log(
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8164
|
+
chalk3.gray(" Run"),
|
|
8165
|
+
chalk3.cyan("baseboards logs"),
|
|
8166
|
+
chalk3.gray("to check progress.")
|
|
8078
8167
|
);
|
|
8079
8168
|
}
|
|
8080
8169
|
}
|
|
8081
8170
|
async function runMigrations(ctx) {
|
|
8082
8171
|
const spinner = ora2("Running database migrations...").start();
|
|
8083
8172
|
try {
|
|
8084
|
-
const { stdout } = await
|
|
8173
|
+
const { stdout } = await execa3(
|
|
8085
8174
|
"docker",
|
|
8086
8175
|
[
|
|
8087
8176
|
...getComposeBaseArgs(ctx),
|
|
@@ -8097,12 +8186,12 @@ async function runMigrations(ctx) {
|
|
|
8097
8186
|
}
|
|
8098
8187
|
);
|
|
8099
8188
|
if (stdout && (stdout.includes("Running upgrade") || process.env.DEBUG)) {
|
|
8100
|
-
console.log(
|
|
8101
|
-
console.log(
|
|
8189
|
+
console.log(chalk3.gray("\n Migration output:"));
|
|
8190
|
+
console.log(chalk3.gray(" " + stdout.split("\n").join("\n ")));
|
|
8102
8191
|
}
|
|
8103
8192
|
spinner.succeed("Database migrations complete");
|
|
8104
8193
|
spinner.start("Restarting API to apply migrations...");
|
|
8105
|
-
await
|
|
8194
|
+
await execa3(
|
|
8106
8195
|
"docker",
|
|
8107
8196
|
[...getComposeBaseArgs(ctx), "restart", "api"],
|
|
8108
8197
|
{
|
|
@@ -8117,42 +8206,42 @@ async function runMigrations(ctx) {
|
|
|
8117
8206
|
const isPasswordError = errorMessage.includes("password authentication failed") || errorMessage.includes("InvalidPasswordError");
|
|
8118
8207
|
if (isPasswordError) {
|
|
8119
8208
|
console.log(
|
|
8120
|
-
|
|
8209
|
+
chalk3.red(
|
|
8121
8210
|
"\n\u274C Database password mismatch - cannot connect to existing database"
|
|
8122
8211
|
)
|
|
8123
8212
|
);
|
|
8124
8213
|
console.log(
|
|
8125
|
-
|
|
8214
|
+
chalk3.yellow(
|
|
8126
8215
|
" Existing database volumes have a different password than the current configuration."
|
|
8127
8216
|
)
|
|
8128
8217
|
);
|
|
8129
|
-
console.log(
|
|
8218
|
+
console.log(chalk3.yellow("\n To fix this, choose one of:"));
|
|
8130
8219
|
console.log(
|
|
8131
|
-
|
|
8220
|
+
chalk3.cyan(" 1. Start fresh (deletes data):") + chalk3.gray(" baseboards down --volumes && baseboards up")
|
|
8132
8221
|
);
|
|
8133
8222
|
console.log(
|
|
8134
|
-
|
|
8223
|
+
chalk3.cyan(" 2. Start fresh automatically:") + chalk3.gray(" baseboards up --fresh")
|
|
8135
8224
|
);
|
|
8136
8225
|
console.log(
|
|
8137
|
-
|
|
8226
|
+
chalk3.gray(
|
|
8138
8227
|
"\n This usually happens when project files were deleted but Docker volumes remain."
|
|
8139
8228
|
)
|
|
8140
8229
|
);
|
|
8141
8230
|
} else {
|
|
8142
8231
|
console.log(
|
|
8143
|
-
|
|
8232
|
+
chalk3.red(
|
|
8144
8233
|
"\n\u274C Database migrations failed"
|
|
8145
8234
|
)
|
|
8146
8235
|
);
|
|
8147
|
-
console.log(
|
|
8148
|
-
console.log(
|
|
8236
|
+
console.log(chalk3.gray("\n Error details:"));
|
|
8237
|
+
console.log(chalk3.gray(" " + errorMessage));
|
|
8149
8238
|
console.log(
|
|
8150
|
-
|
|
8239
|
+
chalk3.yellow(
|
|
8151
8240
|
"\n You can try running migrations manually:"
|
|
8152
8241
|
)
|
|
8153
8242
|
);
|
|
8154
8243
|
console.log(
|
|
8155
|
-
|
|
8244
|
+
chalk3.cyan(" docker compose exec api alembic upgrade head")
|
|
8156
8245
|
);
|
|
8157
8246
|
}
|
|
8158
8247
|
throw new Error("Database migrations failed");
|
|
@@ -8168,84 +8257,87 @@ function getDevCommand(pm) {
|
|
|
8168
8257
|
return commands[pm];
|
|
8169
8258
|
}
|
|
8170
8259
|
function printDefaultSuccessMessage(ctx, hasKeyWarning) {
|
|
8171
|
-
console.log(
|
|
8260
|
+
console.log(chalk3.green.bold("\n\u2705 Baseboards is running!\n"));
|
|
8172
8261
|
console.log(
|
|
8173
|
-
|
|
8174
|
-
|
|
8262
|
+
chalk3.cyan(" Web: "),
|
|
8263
|
+
chalk3.underline(`http://localhost:${ctx.ports.web}`)
|
|
8175
8264
|
);
|
|
8176
8265
|
console.log(
|
|
8177
|
-
|
|
8178
|
-
|
|
8266
|
+
chalk3.cyan(" API: "),
|
|
8267
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}`)
|
|
8179
8268
|
);
|
|
8180
8269
|
console.log(
|
|
8181
|
-
|
|
8182
|
-
|
|
8270
|
+
chalk3.cyan(" GraphQL: "),
|
|
8271
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}/graphql`)
|
|
8183
8272
|
);
|
|
8184
8273
|
if (hasKeyWarning) {
|
|
8185
|
-
console.log(
|
|
8186
|
-
console.log(
|
|
8274
|
+
console.log(chalk3.yellow("\n\u26A0\uFE0F Remember to configure provider API keys!"));
|
|
8275
|
+
console.log(chalk3.gray(" Edit:"), chalk3.cyan("api/.env"));
|
|
8187
8276
|
console.log(
|
|
8188
|
-
|
|
8189
|
-
|
|
8277
|
+
chalk3.gray(" Docs:"),
|
|
8278
|
+
chalk3.cyan("https://baseboards.dev/docs/setup")
|
|
8190
8279
|
);
|
|
8191
8280
|
}
|
|
8192
|
-
console.log(
|
|
8193
|
-
console.log(
|
|
8281
|
+
console.log(chalk3.gray("\nUseful commands:"));
|
|
8282
|
+
console.log(chalk3.gray(" View logs: "), chalk3.cyan("npm run logs"));
|
|
8283
|
+
console.log(chalk3.gray(" Stop: "), chalk3.cyan("npm run down"));
|
|
8194
8284
|
console.log();
|
|
8195
8285
|
}
|
|
8196
8286
|
function printAppDevSuccessMessage(ctx, hasKeyWarning) {
|
|
8197
|
-
console.log(
|
|
8287
|
+
console.log(chalk3.green.bold("\n\u2705 Backend services are running!\n"));
|
|
8198
8288
|
console.log(
|
|
8199
|
-
|
|
8200
|
-
|
|
8289
|
+
chalk3.cyan(" API: "),
|
|
8290
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}`)
|
|
8201
8291
|
);
|
|
8202
8292
|
console.log(
|
|
8203
|
-
|
|
8204
|
-
|
|
8293
|
+
chalk3.cyan(" GraphQL: "),
|
|
8294
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}/graphql`)
|
|
8205
8295
|
);
|
|
8206
|
-
console.log(
|
|
8207
|
-
const relativeWebPath =
|
|
8296
|
+
console.log(chalk3.cyan("\nTo start the frontend:\n"));
|
|
8297
|
+
const relativeWebPath = path6.relative(process.cwd(), path6.join(ctx.dir, "web"));
|
|
8208
8298
|
const cdCommand = relativeWebPath || "web";
|
|
8209
8299
|
const packageManager = ctx.packageManager || "pnpm";
|
|
8210
8300
|
const devCommand = getDevCommand(packageManager);
|
|
8211
|
-
console.log(
|
|
8212
|
-
console.log(
|
|
8213
|
-
console.log(
|
|
8301
|
+
console.log(chalk3.cyan(` cd ${cdCommand}`));
|
|
8302
|
+
console.log(chalk3.cyan(` ${devCommand}`));
|
|
8303
|
+
console.log(chalk3.gray("\nThe frontend will be available at"), chalk3.underline("http://localhost:3000"));
|
|
8214
8304
|
if (hasKeyWarning) {
|
|
8215
|
-
console.log(
|
|
8216
|
-
console.log(
|
|
8305
|
+
console.log(chalk3.yellow("\n\u26A0\uFE0F Remember to configure provider API keys!"));
|
|
8306
|
+
console.log(chalk3.gray(" Edit:"), chalk3.cyan("api/.env"));
|
|
8217
8307
|
}
|
|
8218
|
-
console.log(
|
|
8219
|
-
console.log(
|
|
8308
|
+
console.log(chalk3.gray("\nUseful commands:"));
|
|
8309
|
+
console.log(chalk3.gray(" View logs: "), chalk3.cyan("npm run logs"));
|
|
8310
|
+
console.log(chalk3.gray(" Stop: "), chalk3.cyan("npm run down"));
|
|
8220
8311
|
console.log();
|
|
8221
8312
|
}
|
|
8222
8313
|
function printDevPackagesSuccessMessage(ctx, hasKeyWarning) {
|
|
8223
|
-
console.log(
|
|
8224
|
-
console.log(
|
|
8314
|
+
console.log(chalk3.green.bold("\n\u2705 Backend services are running!"));
|
|
8315
|
+
console.log(chalk3.green.bold("\u2705 Local @weirdfingers/boards package linked!\n"));
|
|
8225
8316
|
console.log(
|
|
8226
|
-
|
|
8227
|
-
|
|
8317
|
+
chalk3.cyan(" API: "),
|
|
8318
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}`)
|
|
8228
8319
|
);
|
|
8229
8320
|
console.log(
|
|
8230
|
-
|
|
8231
|
-
|
|
8321
|
+
chalk3.cyan(" GraphQL: "),
|
|
8322
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}/graphql`)
|
|
8232
8323
|
);
|
|
8233
|
-
console.log(
|
|
8234
|
-
console.log(
|
|
8235
|
-
console.log(
|
|
8236
|
-
console.log(
|
|
8237
|
-
console.log(
|
|
8238
|
-
console.log(
|
|
8239
|
-
console.log(
|
|
8240
|
-
console.log(
|
|
8241
|
-
console.log(
|
|
8324
|
+
console.log(chalk3.cyan("\n\u{1F4E6} Package development workflow:\n"));
|
|
8325
|
+
console.log(chalk3.gray(" 1. Edit package source:"));
|
|
8326
|
+
console.log(chalk3.cyan(` ${ctx.dir}/frontend/src/`));
|
|
8327
|
+
console.log(chalk3.gray("\n 2. Start the frontend:"));
|
|
8328
|
+
console.log(chalk3.cyan(` cd ${ctx.dir}/web`));
|
|
8329
|
+
console.log(chalk3.cyan(` pnpm install`));
|
|
8330
|
+
console.log(chalk3.cyan(` pnpm dev`));
|
|
8331
|
+
console.log(chalk3.gray("\n 3. Changes to the package will hot-reload automatically"));
|
|
8332
|
+
console.log(chalk3.gray(`
|
|
8242
8333
|
Frontend will be available at http://localhost:3000`));
|
|
8243
8334
|
if (hasKeyWarning) {
|
|
8244
|
-
console.log(
|
|
8245
|
-
console.log(
|
|
8335
|
+
console.log(chalk3.yellow("\n\u26A0\uFE0F Remember to configure provider API keys!"));
|
|
8336
|
+
console.log(chalk3.gray(" Edit:"), chalk3.cyan("api/.env"));
|
|
8246
8337
|
}
|
|
8247
|
-
console.log(
|
|
8248
|
-
console.log(
|
|
8338
|
+
console.log(chalk3.gray("\nUseful commands:"));
|
|
8339
|
+
console.log(chalk3.gray(" View logs: "), chalk3.cyan("npm run logs"));
|
|
8340
|
+
console.log(chalk3.gray(" Stop: "), chalk3.cyan("npm run down"));
|
|
8249
8341
|
console.log();
|
|
8250
8342
|
}
|
|
8251
8343
|
function printSuccessMessage(ctx, detached, hasKeyWarning) {
|
|
@@ -8259,7 +8351,7 @@ function printSuccessMessage(ctx, detached, hasKeyWarning) {
|
|
|
8259
8351
|
}
|
|
8260
8352
|
async function checkForExistingVolumes() {
|
|
8261
8353
|
try {
|
|
8262
|
-
const { stdout } = await
|
|
8354
|
+
const { stdout } = await execa3("docker", [
|
|
8263
8355
|
"volume",
|
|
8264
8356
|
"ls",
|
|
8265
8357
|
"--format",
|
|
@@ -8276,14 +8368,14 @@ async function cleanupDockerVolumes(ctx) {
|
|
|
8276
8368
|
const spinner = ora2("Cleaning up Docker volumes...").start();
|
|
8277
8369
|
try {
|
|
8278
8370
|
if (ctx.isScaffolded) {
|
|
8279
|
-
await
|
|
8371
|
+
await execa3("docker", [...getComposeBaseArgs(ctx), "down", "-v"], {
|
|
8280
8372
|
cwd: ctx.dir
|
|
8281
8373
|
});
|
|
8282
8374
|
} else {
|
|
8283
8375
|
const volumesToRemove = ["baseboards_db-data", "baseboards_api-storage"];
|
|
8284
8376
|
for (const volumeName of volumesToRemove) {
|
|
8285
8377
|
try {
|
|
8286
|
-
await
|
|
8378
|
+
await execa3("docker", ["volume", "rm", volumeName]);
|
|
8287
8379
|
spinner.text = `Removing volume ${volumeName}...`;
|
|
8288
8380
|
} catch {
|
|
8289
8381
|
}
|
|
@@ -8293,25 +8385,25 @@ async function cleanupDockerVolumes(ctx) {
|
|
|
8293
8385
|
} catch (error) {
|
|
8294
8386
|
spinner.fail("Failed to clean up volumes");
|
|
8295
8387
|
console.log(
|
|
8296
|
-
|
|
8388
|
+
chalk3.yellow(
|
|
8297
8389
|
"\n\u26A0\uFE0F Could not clean up volumes automatically. Try manually:"
|
|
8298
8390
|
)
|
|
8299
8391
|
);
|
|
8300
|
-
console.log(
|
|
8392
|
+
console.log(chalk3.cyan(" docker volume rm baseboards_db-data"));
|
|
8301
8393
|
throw error;
|
|
8302
8394
|
}
|
|
8303
8395
|
}
|
|
8304
8396
|
|
|
8305
8397
|
// src/commands/down.ts
|
|
8306
|
-
import { execa as
|
|
8307
|
-
import
|
|
8308
|
-
import
|
|
8398
|
+
import { execa as execa4 } from "execa";
|
|
8399
|
+
import path7 from "path";
|
|
8400
|
+
import chalk4 from "chalk";
|
|
8309
8401
|
import ora3 from "ora";
|
|
8310
8402
|
async function down(directory, options) {
|
|
8311
|
-
const dir =
|
|
8403
|
+
const dir = path7.resolve(process.cwd(), directory);
|
|
8312
8404
|
if (!isScaffolded(dir)) {
|
|
8313
|
-
console.error(
|
|
8314
|
-
console.log(
|
|
8405
|
+
console.error(chalk4.red("\n\u274C Error: Not a Baseboards project"));
|
|
8406
|
+
console.log(chalk4.gray(" Run"), chalk4.cyan("baseboards up"), chalk4.gray("to scaffold a project first."));
|
|
8315
8407
|
process.exit(1);
|
|
8316
8408
|
}
|
|
8317
8409
|
const spinner = ora3("Stopping services...").start();
|
|
@@ -8320,12 +8412,12 @@ async function down(directory, options) {
|
|
|
8320
8412
|
args.push("--volumes");
|
|
8321
8413
|
}
|
|
8322
8414
|
try {
|
|
8323
|
-
await
|
|
8415
|
+
await execa4("docker", args, {
|
|
8324
8416
|
cwd: dir
|
|
8325
8417
|
});
|
|
8326
8418
|
spinner.succeed("Services stopped");
|
|
8327
8419
|
if (options.volumes) {
|
|
8328
|
-
console.log(
|
|
8420
|
+
console.log(chalk4.yellow("\u26A0\uFE0F Volumes removed (database data deleted)"));
|
|
8329
8421
|
}
|
|
8330
8422
|
} catch (error) {
|
|
8331
8423
|
spinner.fail("Failed to stop services");
|
|
@@ -8334,14 +8426,14 @@ async function down(directory, options) {
|
|
|
8334
8426
|
}
|
|
8335
8427
|
|
|
8336
8428
|
// src/commands/logs.ts
|
|
8337
|
-
import { execa as
|
|
8338
|
-
import
|
|
8339
|
-
import
|
|
8429
|
+
import { execa as execa5 } from "execa";
|
|
8430
|
+
import path8 from "path";
|
|
8431
|
+
import chalk5 from "chalk";
|
|
8340
8432
|
async function logs(directory, services, options) {
|
|
8341
|
-
const dir =
|
|
8433
|
+
const dir = path8.resolve(process.cwd(), directory);
|
|
8342
8434
|
if (!isScaffolded(dir)) {
|
|
8343
|
-
console.error(
|
|
8344
|
-
console.log(
|
|
8435
|
+
console.error(chalk5.red("\n\u274C Error: Not a Baseboards project"));
|
|
8436
|
+
console.log(chalk5.gray(" Run"), chalk5.cyan("baseboards up"), chalk5.gray("to scaffold a project first."));
|
|
8345
8437
|
process.exit(1);
|
|
8346
8438
|
}
|
|
8347
8439
|
const args = ["compose", "logs"];
|
|
@@ -8358,7 +8450,7 @@ async function logs(directory, services, options) {
|
|
|
8358
8450
|
args.push(...services);
|
|
8359
8451
|
}
|
|
8360
8452
|
try {
|
|
8361
|
-
await
|
|
8453
|
+
await execa5("docker", args, {
|
|
8362
8454
|
cwd: dir,
|
|
8363
8455
|
stdio: "inherit"
|
|
8364
8456
|
});
|
|
@@ -8370,46 +8462,46 @@ async function logs(directory, services, options) {
|
|
|
8370
8462
|
}
|
|
8371
8463
|
|
|
8372
8464
|
// src/commands/status.ts
|
|
8373
|
-
import { execa as
|
|
8374
|
-
import
|
|
8375
|
-
import
|
|
8465
|
+
import { execa as execa6 } from "execa";
|
|
8466
|
+
import path9 from "path";
|
|
8467
|
+
import chalk6 from "chalk";
|
|
8376
8468
|
async function status(directory) {
|
|
8377
|
-
const dir =
|
|
8469
|
+
const dir = path9.resolve(process.cwd(), directory);
|
|
8378
8470
|
if (!isScaffolded(dir)) {
|
|
8379
|
-
console.error(
|
|
8380
|
-
console.log(
|
|
8471
|
+
console.error(chalk6.red("\n\u274C Error: Not a Baseboards project"));
|
|
8472
|
+
console.log(chalk6.gray(" Run"), chalk6.cyan("baseboards up"), chalk6.gray("to scaffold a project first."));
|
|
8381
8473
|
process.exit(1);
|
|
8382
8474
|
}
|
|
8383
|
-
console.log(
|
|
8475
|
+
console.log(chalk6.blue.bold("\n\u{1F4CA} Service Status\n"));
|
|
8384
8476
|
try {
|
|
8385
|
-
await
|
|
8477
|
+
await execa6("docker", ["compose", "ps"], {
|
|
8386
8478
|
cwd: dir,
|
|
8387
8479
|
stdio: "inherit"
|
|
8388
8480
|
});
|
|
8389
8481
|
} catch (error) {
|
|
8390
|
-
console.error(
|
|
8482
|
+
console.error(chalk6.red("\n\u274C Failed to get status"));
|
|
8391
8483
|
throw error;
|
|
8392
8484
|
}
|
|
8393
8485
|
}
|
|
8394
8486
|
|
|
8395
8487
|
// src/commands/clean.ts
|
|
8396
|
-
import { execa as
|
|
8397
|
-
import
|
|
8398
|
-
import
|
|
8488
|
+
import { execa as execa7 } from "execa";
|
|
8489
|
+
import path10 from "path";
|
|
8490
|
+
import chalk7 from "chalk";
|
|
8399
8491
|
import ora4 from "ora";
|
|
8400
8492
|
import prompts3 from "prompts";
|
|
8401
8493
|
async function clean(directory, options) {
|
|
8402
|
-
const dir =
|
|
8494
|
+
const dir = path10.resolve(process.cwd(), directory);
|
|
8403
8495
|
if (!isScaffolded(dir)) {
|
|
8404
|
-
console.error(
|
|
8405
|
-
console.log(
|
|
8496
|
+
console.error(chalk7.red("\n\u274C Error: Not a Baseboards project"));
|
|
8497
|
+
console.log(chalk7.gray(" Run"), chalk7.cyan("baseboards up"), chalk7.gray("to scaffold a project first."));
|
|
8406
8498
|
process.exit(1);
|
|
8407
8499
|
}
|
|
8408
8500
|
if (options.hard) {
|
|
8409
|
-
console.log(
|
|
8410
|
-
console.log(
|
|
8411
|
-
console.log(
|
|
8412
|
-
console.log(
|
|
8501
|
+
console.log(chalk7.yellow("\n\u26A0\uFE0F WARNING: This will delete:"));
|
|
8502
|
+
console.log(chalk7.yellow(" \u2022 All containers"));
|
|
8503
|
+
console.log(chalk7.yellow(" \u2022 All volumes (database data will be lost)"));
|
|
8504
|
+
console.log(chalk7.yellow(" \u2022 All images"));
|
|
8413
8505
|
const response = await prompts3({
|
|
8414
8506
|
type: "confirm",
|
|
8415
8507
|
name: "confirmed",
|
|
@@ -8417,33 +8509,33 @@ async function clean(directory, options) {
|
|
|
8417
8509
|
initial: false
|
|
8418
8510
|
});
|
|
8419
8511
|
if (!response.confirmed) {
|
|
8420
|
-
console.log(
|
|
8512
|
+
console.log(chalk7.gray("\nCancelled"));
|
|
8421
8513
|
return;
|
|
8422
8514
|
}
|
|
8423
8515
|
}
|
|
8424
8516
|
const spinner = ora4("Cleaning up...").start();
|
|
8425
8517
|
try {
|
|
8426
|
-
await
|
|
8518
|
+
await execa7("docker", ["compose", "down", "--volumes", "--remove-orphans"], {
|
|
8427
8519
|
cwd: dir
|
|
8428
8520
|
});
|
|
8429
8521
|
if (options.hard) {
|
|
8430
8522
|
try {
|
|
8431
|
-
const { stdout } = await
|
|
8523
|
+
const { stdout } = await execa7("docker", ["compose", "images", "-q"], {
|
|
8432
8524
|
cwd: dir
|
|
8433
8525
|
});
|
|
8434
8526
|
const imageIds = stdout.split("\n").filter(Boolean);
|
|
8435
8527
|
if (imageIds.length > 0) {
|
|
8436
|
-
await
|
|
8528
|
+
await execa7("docker", ["rmi", ...imageIds]);
|
|
8437
8529
|
}
|
|
8438
8530
|
} catch (e) {
|
|
8439
8531
|
}
|
|
8440
8532
|
}
|
|
8441
8533
|
spinner.succeed("Cleanup complete");
|
|
8442
8534
|
if (options.hard) {
|
|
8443
|
-
console.log(
|
|
8444
|
-
console.log(
|
|
8535
|
+
console.log(chalk7.green("\n\u2728 All Docker resources removed"));
|
|
8536
|
+
console.log(chalk7.gray(" Run"), chalk7.cyan("baseboards up"), chalk7.gray("to start fresh."));
|
|
8445
8537
|
} else {
|
|
8446
|
-
console.log(
|
|
8538
|
+
console.log(chalk7.green("\n\u2728 Containers and volumes removed"));
|
|
8447
8539
|
}
|
|
8448
8540
|
} catch (error) {
|
|
8449
8541
|
spinner.fail("Cleanup failed");
|
|
@@ -8452,34 +8544,34 @@ async function clean(directory, options) {
|
|
|
8452
8544
|
}
|
|
8453
8545
|
|
|
8454
8546
|
// src/commands/update.ts
|
|
8455
|
-
import
|
|
8456
|
-
import
|
|
8547
|
+
import path11 from "path";
|
|
8548
|
+
import chalk8 from "chalk";
|
|
8457
8549
|
async function update(directory, options) {
|
|
8458
|
-
const dir =
|
|
8550
|
+
const dir = path11.resolve(process.cwd(), directory);
|
|
8459
8551
|
if (!isScaffolded(dir)) {
|
|
8460
|
-
console.error(
|
|
8461
|
-
console.log(
|
|
8552
|
+
console.error(chalk8.red("\n\u274C Error: Not a Baseboards project"));
|
|
8553
|
+
console.log(chalk8.gray(" Run"), chalk8.cyan("baseboards up"), chalk8.gray("to scaffold a project first."));
|
|
8462
8554
|
process.exit(1);
|
|
8463
8555
|
}
|
|
8464
|
-
console.log(
|
|
8465
|
-
console.log(
|
|
8466
|
-
console.log(
|
|
8467
|
-
console.log(
|
|
8468
|
-
console.log(
|
|
8469
|
-
console.log(
|
|
8556
|
+
console.log(chalk8.blue.bold("\n\u{1F504} Update Command\n"));
|
|
8557
|
+
console.log(chalk8.yellow("\u26A0\uFE0F This feature is coming soon!"));
|
|
8558
|
+
console.log(chalk8.gray("\nFor now, to update:"));
|
|
8559
|
+
console.log(chalk8.gray("1. Update the CLI:"), chalk8.cyan("npm install -g @weirdfingers/baseboards@latest"));
|
|
8560
|
+
console.log(chalk8.gray("2. Pull new images:"), chalk8.cyan("docker compose pull"));
|
|
8561
|
+
console.log(chalk8.gray("3. Restart:"), chalk8.cyan("baseboards down && baseboards up"));
|
|
8470
8562
|
console.log();
|
|
8471
8563
|
}
|
|
8472
8564
|
|
|
8473
8565
|
// src/commands/upgrade.ts
|
|
8474
|
-
import
|
|
8475
|
-
import
|
|
8566
|
+
import path16 from "path";
|
|
8567
|
+
import chalk11 from "chalk";
|
|
8476
8568
|
import prompts4 from "prompts";
|
|
8477
8569
|
|
|
8478
8570
|
// src/utils/mode-detection.ts
|
|
8479
8571
|
import { exec } from "child_process";
|
|
8480
8572
|
import { promisify } from "util";
|
|
8481
|
-
import
|
|
8482
|
-
import
|
|
8573
|
+
import path12 from "path";
|
|
8574
|
+
import fs7 from "fs-extra";
|
|
8483
8575
|
var execAsync2 = promisify(exec);
|
|
8484
8576
|
async function detectProjectMode(projectDir) {
|
|
8485
8577
|
try {
|
|
@@ -8490,15 +8582,15 @@ async function detectProjectMode(projectDir) {
|
|
|
8490
8582
|
}
|
|
8491
8583
|
} catch {
|
|
8492
8584
|
}
|
|
8493
|
-
const modeFile =
|
|
8494
|
-
if (await
|
|
8495
|
-
const mode = (await
|
|
8585
|
+
const modeFile = path12.join(projectDir, ".baseboards-mode");
|
|
8586
|
+
if (await fs7.pathExists(modeFile)) {
|
|
8587
|
+
const mode = (await fs7.readFile(modeFile, "utf-8")).trim();
|
|
8496
8588
|
if (mode === "default" || mode === "app-dev") {
|
|
8497
8589
|
return mode;
|
|
8498
8590
|
}
|
|
8499
8591
|
}
|
|
8500
|
-
const webNodeModules =
|
|
8501
|
-
if (await
|
|
8592
|
+
const webNodeModules = path12.join(projectDir, "web", "node_modules");
|
|
8593
|
+
if (await fs7.pathExists(webNodeModules)) {
|
|
8502
8594
|
return "app-dev";
|
|
8503
8595
|
}
|
|
8504
8596
|
return "default";
|
|
@@ -8509,8 +8601,8 @@ import semver from "semver";
|
|
|
8509
8601
|
|
|
8510
8602
|
// src/utils/compatibility-fetcher.ts
|
|
8511
8603
|
var import_ajv = __toESM(require_ajv(), 1);
|
|
8512
|
-
import
|
|
8513
|
-
import
|
|
8604
|
+
import fs8 from "fs-extra";
|
|
8605
|
+
import path13 from "path";
|
|
8514
8606
|
import os from "os";
|
|
8515
8607
|
import addFormats from "ajv-formats";
|
|
8516
8608
|
|
|
@@ -8573,7 +8665,7 @@ var compatibility_manifest_schema_default = {
|
|
|
8573
8665
|
|
|
8574
8666
|
// src/utils/compatibility-fetcher.ts
|
|
8575
8667
|
var GITHUB_REPO = "weirdfingers/boards";
|
|
8576
|
-
var CACHE_DIR =
|
|
8668
|
+
var CACHE_DIR = path13.join(os.homedir(), ".baseboards", "compatibility");
|
|
8577
8669
|
var ajv = new import_ajv.default({ strict: false });
|
|
8578
8670
|
addFormats(ajv);
|
|
8579
8671
|
var validateManifest = ajv.compile(compatibility_manifest_schema_default);
|
|
@@ -8621,31 +8713,31 @@ function getManifestUrl(version) {
|
|
|
8621
8713
|
}
|
|
8622
8714
|
async function loadFromCache(version) {
|
|
8623
8715
|
const cachePath = getCachePath(version);
|
|
8624
|
-
if (!await
|
|
8716
|
+
if (!await fs8.pathExists(cachePath)) {
|
|
8625
8717
|
return null;
|
|
8626
8718
|
}
|
|
8627
8719
|
try {
|
|
8628
|
-
const content = await
|
|
8720
|
+
const content = await fs8.readFile(cachePath, "utf-8");
|
|
8629
8721
|
const manifest = JSON.parse(content);
|
|
8630
8722
|
if (!validateManifest(manifest)) {
|
|
8631
|
-
await
|
|
8723
|
+
await fs8.remove(cachePath);
|
|
8632
8724
|
return null;
|
|
8633
8725
|
}
|
|
8634
8726
|
return manifest;
|
|
8635
8727
|
} catch (error) {
|
|
8636
|
-
await
|
|
8728
|
+
await fs8.remove(cachePath).catch(() => {
|
|
8637
8729
|
});
|
|
8638
8730
|
return null;
|
|
8639
8731
|
}
|
|
8640
8732
|
}
|
|
8641
8733
|
async function saveToCache(version, manifest) {
|
|
8642
8734
|
const cachePath = getCachePath(version);
|
|
8643
|
-
await
|
|
8644
|
-
await
|
|
8735
|
+
await fs8.ensureDir(CACHE_DIR);
|
|
8736
|
+
await fs8.writeFile(cachePath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
8645
8737
|
}
|
|
8646
8738
|
function getCachePath(version) {
|
|
8647
8739
|
const cleanVersion = version.replace(/^v/, "");
|
|
8648
|
-
return
|
|
8740
|
+
return path13.join(CACHE_DIR, `compatibility-${cleanVersion}.json`);
|
|
8649
8741
|
}
|
|
8650
8742
|
|
|
8651
8743
|
// src/utils/compatibility-checker.ts
|
|
@@ -8697,70 +8789,70 @@ function isVersionAffected(version, affectedRange) {
|
|
|
8697
8789
|
}
|
|
8698
8790
|
|
|
8699
8791
|
// src/commands/upgrade-default.ts
|
|
8700
|
-
import
|
|
8701
|
-
import
|
|
8702
|
-
import
|
|
8703
|
-
import { execa as
|
|
8792
|
+
import path14 from "path";
|
|
8793
|
+
import fs9 from "fs-extra";
|
|
8794
|
+
import chalk9 from "chalk";
|
|
8795
|
+
import { execa as execa8 } from "execa";
|
|
8704
8796
|
import ora5 from "ora";
|
|
8705
8797
|
async function upgradeDefaultMode(projectDir, currentVersion, targetVersion) {
|
|
8706
|
-
console.log(
|
|
8798
|
+
console.log(chalk9.blue(`
|
|
8707
8799
|
\u{1F4E6} Upgrading from v${currentVersion} to v${targetVersion}
|
|
8708
8800
|
`));
|
|
8709
8801
|
try {
|
|
8710
|
-
console.log(
|
|
8802
|
+
console.log(chalk9.gray("\u23F8\uFE0F Stopping services..."));
|
|
8711
8803
|
await execAsync3("docker compose --env-file docker/.env down", { cwd: projectDir });
|
|
8712
|
-
console.log(
|
|
8804
|
+
console.log(chalk9.gray("\u2B07\uFE0F Pulling new backend images..."));
|
|
8713
8805
|
await execAsync3("docker compose --env-file docker/.env pull api worker", { cwd: projectDir });
|
|
8714
|
-
console.log(
|
|
8806
|
+
console.log(chalk9.gray("\u{1F4DD} Updating frontend dependencies..."));
|
|
8715
8807
|
await updateWebPackageJson(projectDir, targetVersion);
|
|
8716
|
-
console.log(
|
|
8808
|
+
console.log(chalk9.gray("\u{1F528} Rebuilding frontend image (this may take a few minutes)..."));
|
|
8717
8809
|
await execAsync3("docker compose --env-file docker/.env build web", { cwd: projectDir });
|
|
8718
|
-
console.log(
|
|
8810
|
+
console.log(chalk9.gray("\u2699\uFE0F Updating configuration..."));
|
|
8719
8811
|
await updateEnvVersion(projectDir, targetVersion);
|
|
8720
|
-
console.log(
|
|
8812
|
+
console.log(chalk9.gray("\u{1F680} Starting services..."));
|
|
8721
8813
|
await execAsync3("docker compose --env-file docker/.env up -d", { cwd: projectDir });
|
|
8722
|
-
console.log(
|
|
8814
|
+
console.log(chalk9.gray("\u{1F3E5} Waiting for services to be healthy..."));
|
|
8723
8815
|
await waitForHealth(projectDir, ["db", "cache", "api", "worker", "web"]);
|
|
8724
|
-
console.log(
|
|
8816
|
+
console.log(chalk9.green(`
|
|
8725
8817
|
\u2705 Successfully upgraded to v${targetVersion}!
|
|
8726
8818
|
`));
|
|
8727
8819
|
printUpgradeSuccess(projectDir, targetVersion);
|
|
8728
8820
|
} catch (error) {
|
|
8729
8821
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
8730
|
-
console.error(
|
|
8822
|
+
console.error(chalk9.red(`
|
|
8731
8823
|
\u274C Upgrade failed: ${errorMessage}
|
|
8732
8824
|
`));
|
|
8733
|
-
console.log(
|
|
8734
|
-
console.log(
|
|
8735
|
-
console.log(
|
|
8736
|
-
console.log(
|
|
8737
|
-
console.log(
|
|
8825
|
+
console.log(chalk9.yellow("To rollback:"));
|
|
8826
|
+
console.log(chalk9.gray(` 1. Edit docker/.env and set BACKEND_VERSION=${currentVersion}`));
|
|
8827
|
+
console.log(chalk9.gray(" 2. Run: docker compose pull"));
|
|
8828
|
+
console.log(chalk9.gray(" 3. Run: docker compose build web"));
|
|
8829
|
+
console.log(chalk9.gray(" 4. Run: docker compose up -d\n"));
|
|
8738
8830
|
throw error;
|
|
8739
8831
|
}
|
|
8740
8832
|
}
|
|
8741
8833
|
async function updateWebPackageJson(projectDir, version) {
|
|
8742
|
-
const packageJsonPath =
|
|
8743
|
-
const packageJson2 = await
|
|
8834
|
+
const packageJsonPath = path14.join(projectDir, "web", "package.json");
|
|
8835
|
+
const packageJson2 = await fs9.readJson(packageJsonPath);
|
|
8744
8836
|
if (packageJson2.dependencies && packageJson2.dependencies["@weirdfingers/boards"]) {
|
|
8745
8837
|
packageJson2.dependencies["@weirdfingers/boards"] = version;
|
|
8746
8838
|
}
|
|
8747
|
-
await
|
|
8839
|
+
await fs9.writeJson(packageJsonPath, packageJson2, { spaces: 2 });
|
|
8748
8840
|
}
|
|
8749
8841
|
async function updateEnvVersion(projectDir, version) {
|
|
8750
|
-
const envPath =
|
|
8751
|
-
let content = await
|
|
8842
|
+
const envPath = path14.join(projectDir, "docker", ".env");
|
|
8843
|
+
let content = await fs9.readFile(envPath, "utf-8");
|
|
8752
8844
|
content = content.replace(
|
|
8753
8845
|
/^BACKEND_VERSION=.*/m,
|
|
8754
8846
|
`BACKEND_VERSION=${version}`
|
|
8755
8847
|
);
|
|
8756
|
-
await
|
|
8848
|
+
await fs9.writeFile(envPath, content, "utf-8");
|
|
8757
8849
|
}
|
|
8758
8850
|
async function waitForHealth(projectDir, services) {
|
|
8759
8851
|
const spinner = ora5("Waiting for services to be healthy...").start();
|
|
8760
8852
|
const maxWaitMs = 12e4;
|
|
8761
8853
|
const checkHealth = async () => {
|
|
8762
8854
|
try {
|
|
8763
|
-
const { stdout } = await
|
|
8855
|
+
const { stdout } = await execa8(
|
|
8764
8856
|
"docker",
|
|
8765
8857
|
["compose", "--env-file", "docker/.env", "ps", "--format", "json"],
|
|
8766
8858
|
{
|
|
@@ -8790,106 +8882,106 @@ async function waitForHealth(projectDir, services) {
|
|
|
8790
8882
|
} else {
|
|
8791
8883
|
spinner.warn("Services taking longer than expected...");
|
|
8792
8884
|
console.log(
|
|
8793
|
-
|
|
8885
|
+
chalk9.yellow(
|
|
8794
8886
|
"\n\u26A0\uFE0F Health check timeout. Services may still be starting."
|
|
8795
8887
|
)
|
|
8796
8888
|
);
|
|
8797
8889
|
console.log(
|
|
8798
|
-
|
|
8799
|
-
|
|
8800
|
-
|
|
8890
|
+
chalk9.gray(" Run"),
|
|
8891
|
+
chalk9.cyan("baseboards logs"),
|
|
8892
|
+
chalk9.gray("to check progress.")
|
|
8801
8893
|
);
|
|
8802
8894
|
}
|
|
8803
8895
|
}
|
|
8804
8896
|
function printUpgradeSuccess(projectDir, version) {
|
|
8805
|
-
console.log(
|
|
8806
|
-
console.log(
|
|
8807
|
-
console.log(
|
|
8808
|
-
console.log(
|
|
8809
|
-
console.log(
|
|
8810
|
-
console.log(
|
|
8897
|
+
console.log(chalk9.gray(" Your Baseboards installation has been upgraded."));
|
|
8898
|
+
console.log(chalk9.gray(" All services are running and healthy.\n"));
|
|
8899
|
+
console.log(chalk9.gray("Next steps:"));
|
|
8900
|
+
console.log(chalk9.gray(` \u2022 Check release notes: https://github.com/weirdfingers/boards/releases/tag/v${version}`));
|
|
8901
|
+
console.log(chalk9.gray(` \u2022 View logs: baseboards logs ${path14.basename(projectDir)}`));
|
|
8902
|
+
console.log(chalk9.gray(` \u2022 Check status: baseboards status ${path14.basename(projectDir)}
|
|
8811
8903
|
`));
|
|
8812
8904
|
}
|
|
8813
8905
|
async function execAsync3(command, options) {
|
|
8814
8906
|
const [cmd, ...args] = command.split(" ");
|
|
8815
|
-
return
|
|
8907
|
+
return execa8(cmd, args, options);
|
|
8816
8908
|
}
|
|
8817
8909
|
|
|
8818
8910
|
// src/commands/upgrade-app-dev.ts
|
|
8819
|
-
import
|
|
8820
|
-
import
|
|
8821
|
-
import
|
|
8822
|
-
import { execa as
|
|
8911
|
+
import path15 from "path";
|
|
8912
|
+
import fs10 from "fs-extra";
|
|
8913
|
+
import chalk10 from "chalk";
|
|
8914
|
+
import { execa as execa9 } from "execa";
|
|
8823
8915
|
import ora6 from "ora";
|
|
8824
8916
|
async function upgradeAppDevMode(projectDir, currentVersion, targetVersion) {
|
|
8825
|
-
console.log(
|
|
8917
|
+
console.log(chalk10.blue(`
|
|
8826
8918
|
\u{1F4E6} Upgrading backend from v${currentVersion} to v${targetVersion}
|
|
8827
8919
|
`));
|
|
8828
8920
|
try {
|
|
8829
|
-
console.log(
|
|
8921
|
+
console.log(chalk10.gray("\u23F8\uFE0F Stopping backend services..."));
|
|
8830
8922
|
await execAsync("docker compose --env-file docker/.env down", { cwd: projectDir });
|
|
8831
|
-
console.log(
|
|
8923
|
+
console.log(chalk10.gray("\u2B07\uFE0F Pulling new backend images..."));
|
|
8832
8924
|
await execAsync("docker compose --env-file docker/.env pull api worker", { cwd: projectDir });
|
|
8833
|
-
console.log(
|
|
8925
|
+
console.log(chalk10.gray("\u2699\uFE0F Updating configuration..."));
|
|
8834
8926
|
await updateEnvVersion2(projectDir, targetVersion);
|
|
8835
|
-
console.log(
|
|
8927
|
+
console.log(chalk10.gray("\u{1F680} Starting backend services..."));
|
|
8836
8928
|
await execAsync("docker compose --env-file docker/.env up -d db cache api worker", { cwd: projectDir });
|
|
8837
|
-
console.log(
|
|
8929
|
+
console.log(chalk10.gray("\u{1F3E5} Waiting for backend to be healthy..."));
|
|
8838
8930
|
await waitForHealth2(projectDir, ["db", "cache", "api", "worker"]);
|
|
8839
|
-
console.log(
|
|
8931
|
+
console.log(chalk10.green(`
|
|
8840
8932
|
\u2705 Backend upgraded to v${targetVersion}!
|
|
8841
8933
|
`));
|
|
8842
8934
|
await printAppDevUpgradeInstructions(projectDir, currentVersion, targetVersion);
|
|
8843
8935
|
} catch (error) {
|
|
8844
8936
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
8845
|
-
console.error(
|
|
8937
|
+
console.error(chalk10.red(`
|
|
8846
8938
|
\u274C Upgrade failed: ${errorMessage}
|
|
8847
8939
|
`));
|
|
8848
|
-
console.log(
|
|
8849
|
-
console.log(
|
|
8850
|
-
console.log(
|
|
8851
|
-
console.log(
|
|
8940
|
+
console.log(chalk10.yellow("To rollback:"));
|
|
8941
|
+
console.log(chalk10.gray(` 1. Edit docker/.env and set BACKEND_VERSION=${currentVersion}`));
|
|
8942
|
+
console.log(chalk10.gray(" 2. Run: docker compose --env-file docker/.env pull"));
|
|
8943
|
+
console.log(chalk10.gray(" 3. Run: docker compose --env-file docker/.env up -d db cache api worker\n"));
|
|
8852
8944
|
throw error;
|
|
8853
8945
|
}
|
|
8854
8946
|
}
|
|
8855
8947
|
async function updateEnvVersion2(projectDir, version) {
|
|
8856
|
-
const envPath =
|
|
8857
|
-
let content = await
|
|
8948
|
+
const envPath = path15.join(projectDir, "docker", ".env");
|
|
8949
|
+
let content = await fs10.readFile(envPath, "utf-8");
|
|
8858
8950
|
content = content.replace(
|
|
8859
8951
|
/^BACKEND_VERSION=.*/m,
|
|
8860
8952
|
`BACKEND_VERSION=${version}`
|
|
8861
8953
|
);
|
|
8862
|
-
await
|
|
8954
|
+
await fs10.writeFile(envPath, content, "utf-8");
|
|
8863
8955
|
}
|
|
8864
8956
|
async function printAppDevUpgradeInstructions(projectDir, oldVersion, newVersion) {
|
|
8865
|
-
const webDir =
|
|
8957
|
+
const webDir = path15.join(projectDir, "web");
|
|
8866
8958
|
const packageManager = await detectPackageManager(webDir);
|
|
8867
8959
|
const updateCommand = packageManager === "npm" ? `npm install @weirdfingers/boards@${newVersion}` : packageManager === "yarn" ? `yarn upgrade @weirdfingers/boards@${newVersion}` : packageManager === "bun" ? `bun update @weirdfingers/boards@${newVersion}` : `pnpm update @weirdfingers/boards@${newVersion}`;
|
|
8868
|
-
console.log(
|
|
8869
|
-
console.log(
|
|
8870
|
-
console.log(
|
|
8871
|
-
console.log(
|
|
8872
|
-
console.log(
|
|
8960
|
+
console.log(chalk10.yellow("\u26A0\uFE0F Frontend requires manual upgrade:\n"));
|
|
8961
|
+
console.log(chalk10.gray(" 1. Stop your dev server (Ctrl+C if running)\n"));
|
|
8962
|
+
console.log(chalk10.gray(" 2. Update the frontend package:\n"));
|
|
8963
|
+
console.log(chalk10.cyan(` cd ${path15.basename(projectDir)}/web`));
|
|
8964
|
+
console.log(chalk10.cyan(` ${updateCommand}
|
|
8873
8965
|
`));
|
|
8874
|
-
console.log(
|
|
8875
|
-
console.log(
|
|
8966
|
+
console.log(chalk10.gray(" 3. Check for breaking changes:\n"));
|
|
8967
|
+
console.log(chalk10.gray(` https://github.com/weirdfingers/boards/releases/tag/v${newVersion}
|
|
8876
8968
|
`));
|
|
8877
|
-
console.log(
|
|
8878
|
-
console.log(
|
|
8969
|
+
console.log(chalk10.gray(" 4. Restart your dev server:\n"));
|
|
8970
|
+
console.log(chalk10.cyan(` ${packageManager} dev
|
|
8879
8971
|
`));
|
|
8880
8972
|
try {
|
|
8881
8973
|
const { stdout } = await execAsync("git status --porcelain", { cwd: webDir });
|
|
8882
8974
|
if (stdout.trim()) {
|
|
8883
|
-
console.log(
|
|
8884
|
-
console.log(
|
|
8975
|
+
console.log(chalk10.yellow("\u26A0\uFE0F You have uncommitted changes in web/"));
|
|
8976
|
+
console.log(chalk10.gray(" Consider committing before updating dependencies.\n"));
|
|
8885
8977
|
}
|
|
8886
8978
|
} catch (error) {
|
|
8887
|
-
const gitDir =
|
|
8888
|
-
if (!
|
|
8889
|
-
console.log(
|
|
8979
|
+
const gitDir = path15.join(webDir, ".git");
|
|
8980
|
+
if (!fs10.existsSync(gitDir)) {
|
|
8981
|
+
console.log(chalk10.gray(" Skipping git status check: web/ is not a git repository."));
|
|
8890
8982
|
} else {
|
|
8891
8983
|
console.log(
|
|
8892
|
-
|
|
8984
|
+
chalk10.gray(
|
|
8893
8985
|
" Skipping git status check: git is not available or an error occurred while checking repository status."
|
|
8894
8986
|
)
|
|
8895
8987
|
);
|
|
@@ -8901,7 +8993,7 @@ async function waitForHealth2(projectDir, services) {
|
|
|
8901
8993
|
const maxWaitMs = 12e4;
|
|
8902
8994
|
const checkHealth = async () => {
|
|
8903
8995
|
try {
|
|
8904
|
-
const { stdout } = await
|
|
8996
|
+
const { stdout } = await execa9(
|
|
8905
8997
|
"docker",
|
|
8906
8998
|
["compose", "--env-file", "docker/.env", "ps", "--format", "json"],
|
|
8907
8999
|
{
|
|
@@ -8931,61 +9023,61 @@ async function waitForHealth2(projectDir, services) {
|
|
|
8931
9023
|
} else {
|
|
8932
9024
|
spinner.warn("Services taking longer than expected...");
|
|
8933
9025
|
console.log(
|
|
8934
|
-
|
|
9026
|
+
chalk10.yellow(
|
|
8935
9027
|
"\n\u26A0\uFE0F Health check timeout. Services may still be starting."
|
|
8936
9028
|
)
|
|
8937
9029
|
);
|
|
8938
9030
|
console.log(
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
9031
|
+
chalk10.gray(" Run"),
|
|
9032
|
+
chalk10.cyan("baseboards logs"),
|
|
9033
|
+
chalk10.gray("to check progress.")
|
|
8942
9034
|
);
|
|
8943
9035
|
}
|
|
8944
9036
|
}
|
|
8945
9037
|
|
|
8946
9038
|
// src/commands/upgrade.ts
|
|
8947
9039
|
async function upgrade(directory, options) {
|
|
8948
|
-
const dir =
|
|
9040
|
+
const dir = path16.resolve(process.cwd(), directory);
|
|
8949
9041
|
if (!isScaffolded(dir)) {
|
|
8950
|
-
console.error(
|
|
8951
|
-
console.log(
|
|
9042
|
+
console.error(chalk11.red("\n\u274C Error: Not a Baseboards project"));
|
|
9043
|
+
console.log(chalk11.gray(" Run"), chalk11.cyan("baseboards up"), chalk11.gray("to scaffold a project first."));
|
|
8952
9044
|
process.exit(1);
|
|
8953
9045
|
}
|
|
8954
9046
|
const currentVersion = await getCurrentVersion(dir);
|
|
8955
9047
|
if (!currentVersion) {
|
|
8956
|
-
console.error(
|
|
8957
|
-
console.log(
|
|
9048
|
+
console.error(chalk11.red("\n\u274C Error: Could not determine current version"));
|
|
9049
|
+
console.log(chalk11.gray(" Check docker/.env for VERSION field"));
|
|
8958
9050
|
process.exit(1);
|
|
8959
9051
|
}
|
|
8960
9052
|
const targetVersion = options.version || await getLatestVersion();
|
|
8961
9053
|
if (currentVersion === targetVersion) {
|
|
8962
|
-
console.log(
|
|
9054
|
+
console.log(chalk11.green(`
|
|
8963
9055
|
\u2705 Already at v${targetVersion}`));
|
|
8964
9056
|
return;
|
|
8965
9057
|
}
|
|
8966
9058
|
const compatCheck = await checkCompatibility(currentVersion, targetVersion);
|
|
8967
9059
|
const mode = await detectProjectMode(dir);
|
|
8968
|
-
console.log(
|
|
8969
|
-
console.log(
|
|
8970
|
-
console.log(
|
|
8971
|
-
console.log(
|
|
9060
|
+
console.log(chalk11.blue("\u{1F4CB} Upgrade Plan:\n"));
|
|
9061
|
+
console.log(chalk11.gray(` Current version: ${currentVersion}`));
|
|
9062
|
+
console.log(chalk11.gray(` Target version: ${targetVersion}`));
|
|
9063
|
+
console.log(chalk11.gray(` Project mode: ${mode}`));
|
|
8972
9064
|
console.log("");
|
|
8973
9065
|
if (mode === "default") {
|
|
8974
|
-
console.log(
|
|
8975
|
-
console.log(
|
|
8976
|
-
console.log(
|
|
8977
|
-
console.log(
|
|
8978
|
-
console.log(
|
|
8979
|
-
console.log(
|
|
8980
|
-
console.log(
|
|
8981
|
-
console.log(
|
|
9066
|
+
console.log(chalk11.gray(" Steps:"));
|
|
9067
|
+
console.log(chalk11.gray(" 1. Stop all services"));
|
|
9068
|
+
console.log(chalk11.gray(" 2. Pull new backend images"));
|
|
9069
|
+
console.log(chalk11.gray(" 3. Update web/package.json"));
|
|
9070
|
+
console.log(chalk11.gray(" 4. Rebuild frontend Docker image"));
|
|
9071
|
+
console.log(chalk11.gray(" 5. Update docker/.env"));
|
|
9072
|
+
console.log(chalk11.gray(" 6. Start services"));
|
|
9073
|
+
console.log(chalk11.gray(" 7. Wait for health checks"));
|
|
8982
9074
|
} else {
|
|
8983
|
-
console.log(
|
|
8984
|
-
console.log(
|
|
8985
|
-
console.log(
|
|
8986
|
-
console.log(
|
|
8987
|
-
console.log(
|
|
8988
|
-
console.log(
|
|
9075
|
+
console.log(chalk11.gray(" Steps:"));
|
|
9076
|
+
console.log(chalk11.gray(" 1. Stop backend services"));
|
|
9077
|
+
console.log(chalk11.gray(" 2. Pull new backend images"));
|
|
9078
|
+
console.log(chalk11.gray(" 3. Update docker/.env"));
|
|
9079
|
+
console.log(chalk11.gray(" 4. Start backend services"));
|
|
9080
|
+
console.log(chalk11.gray(" 5. Print manual frontend update instructions"));
|
|
8989
9081
|
}
|
|
8990
9082
|
console.log("");
|
|
8991
9083
|
if (compatCheck.warnings.length > 0) {
|
|
@@ -8993,18 +9085,18 @@ async function upgrade(directory, options) {
|
|
|
8993
9085
|
console.log("");
|
|
8994
9086
|
}
|
|
8995
9087
|
if (compatCheck.requiredActions.length > 0) {
|
|
8996
|
-
console.log(
|
|
9088
|
+
console.log(chalk11.yellow("\u26A0\uFE0F Required manual actions:"));
|
|
8997
9089
|
compatCheck.requiredActions.forEach((action) => {
|
|
8998
|
-
console.log(
|
|
9090
|
+
console.log(chalk11.gray(` \u2022 ${action}`));
|
|
8999
9091
|
});
|
|
9000
9092
|
console.log("");
|
|
9001
9093
|
}
|
|
9002
9094
|
if (options.dryRun) {
|
|
9003
|
-
console.log(
|
|
9095
|
+
console.log(chalk11.blue("\u{1F50D} Dry run complete - no changes made\n"));
|
|
9004
9096
|
return;
|
|
9005
9097
|
}
|
|
9006
9098
|
if (options.force && compatCheck.breaking) {
|
|
9007
|
-
console.log(
|
|
9099
|
+
console.log(chalk11.yellow("\u26A0\uFE0F --force flag used: skipping confirmation despite breaking changes\n"));
|
|
9008
9100
|
}
|
|
9009
9101
|
if (!options.force && compatCheck.breaking) {
|
|
9010
9102
|
const { proceed } = await prompts4({
|
|
@@ -9014,7 +9106,7 @@ async function upgrade(directory, options) {
|
|
|
9014
9106
|
initial: false
|
|
9015
9107
|
});
|
|
9016
9108
|
if (!proceed) {
|
|
9017
|
-
console.log(
|
|
9109
|
+
console.log(chalk11.gray("\nUpgrade cancelled\n"));
|
|
9018
9110
|
return;
|
|
9019
9111
|
}
|
|
9020
9112
|
}
|
|
@@ -9034,104 +9126,104 @@ async function getLatestVersion() {
|
|
|
9034
9126
|
}
|
|
9035
9127
|
|
|
9036
9128
|
// src/commands/doctor.ts
|
|
9037
|
-
import
|
|
9038
|
-
import
|
|
9039
|
-
import
|
|
9129
|
+
import path17 from "path";
|
|
9130
|
+
import fs11 from "fs-extra";
|
|
9131
|
+
import chalk12 from "chalk";
|
|
9040
9132
|
async function doctor(directory) {
|
|
9041
|
-
const dir =
|
|
9042
|
-
console.log(
|
|
9043
|
-
console.log(
|
|
9044
|
-
console.log(
|
|
9133
|
+
const dir = path17.resolve(process.cwd(), directory);
|
|
9134
|
+
console.log(chalk12.blue.bold("\n\u{1FA7A} Baseboards Diagnostics\n"));
|
|
9135
|
+
console.log(chalk12.cyan("CLI Version:"), getCliVersion());
|
|
9136
|
+
console.log(chalk12.cyan("\n\u{1F4CB} Prerequisites:"));
|
|
9045
9137
|
const prereqs = await checkPrerequisites();
|
|
9046
9138
|
console.log(
|
|
9047
|
-
|
|
9048
|
-
prereqs.node.installed ? prereqs.node.satisfies ?
|
|
9139
|
+
chalk12.gray(" Node.js:"),
|
|
9140
|
+
prereqs.node.installed ? prereqs.node.satisfies ? chalk12.green(`\u2713 v${prereqs.node.version}`) : chalk12.yellow(`\u26A0\uFE0F v${prereqs.node.version} (need v20+)`) : chalk12.red("\u2717 Not installed")
|
|
9049
9141
|
);
|
|
9050
9142
|
console.log(
|
|
9051
|
-
|
|
9052
|
-
prereqs.docker.installed ?
|
|
9143
|
+
chalk12.gray(" Docker:"),
|
|
9144
|
+
prereqs.docker.installed ? chalk12.green(`\u2713 v${prereqs.docker.version}`) : chalk12.red("\u2717 Not installed")
|
|
9053
9145
|
);
|
|
9054
9146
|
if (prereqs.docker.composeVersion) {
|
|
9055
9147
|
console.log(
|
|
9056
|
-
|
|
9057
|
-
|
|
9148
|
+
chalk12.gray(" Docker Compose:"),
|
|
9149
|
+
chalk12.green(`\u2713 v${prereqs.docker.composeVersion}`)
|
|
9058
9150
|
);
|
|
9059
9151
|
} else if (prereqs.docker.installed) {
|
|
9060
|
-
console.log(
|
|
9152
|
+
console.log(chalk12.gray(" Docker Compose:"), chalk12.red("\u2717 Not available"));
|
|
9061
9153
|
}
|
|
9062
|
-
console.log(
|
|
9154
|
+
console.log(chalk12.gray(" Platform:"), prereqs.platform.name);
|
|
9063
9155
|
if (prereqs.platform.isWSL) {
|
|
9064
|
-
console.log(
|
|
9156
|
+
console.log(chalk12.gray(" WSL:"), chalk12.blue("\u2713 Detected"));
|
|
9065
9157
|
}
|
|
9066
|
-
console.log(
|
|
9158
|
+
console.log(chalk12.cyan("\n\u{1F4C2} Project:"));
|
|
9067
9159
|
const scaffolded = isScaffolded(dir);
|
|
9068
9160
|
console.log(
|
|
9069
|
-
|
|
9070
|
-
scaffolded ?
|
|
9161
|
+
chalk12.gray(" Scaffolded:"),
|
|
9162
|
+
scaffolded ? chalk12.green("\u2713 Yes") : chalk12.yellow("\u2717 No")
|
|
9071
9163
|
);
|
|
9072
9164
|
if (scaffolded) {
|
|
9073
|
-
console.log(
|
|
9074
|
-
const webPkg =
|
|
9075
|
-
const apiPkg =
|
|
9076
|
-
const composeFile =
|
|
9165
|
+
console.log(chalk12.gray(" Directory:"), dir);
|
|
9166
|
+
const webPkg = path17.join(dir, "web/package.json");
|
|
9167
|
+
const apiPkg = path17.join(dir, "api/pyproject.toml");
|
|
9168
|
+
const composeFile = path17.join(dir, "compose.yaml");
|
|
9077
9169
|
console.log(
|
|
9078
|
-
|
|
9079
|
-
|
|
9170
|
+
chalk12.gray(" Web package:"),
|
|
9171
|
+
fs11.existsSync(webPkg) ? chalk12.green("\u2713") : chalk12.red("\u2717")
|
|
9080
9172
|
);
|
|
9081
9173
|
console.log(
|
|
9082
|
-
|
|
9083
|
-
|
|
9174
|
+
chalk12.gray(" API package:"),
|
|
9175
|
+
fs11.existsSync(apiPkg) ? chalk12.green("\u2713") : chalk12.red("\u2717")
|
|
9084
9176
|
);
|
|
9085
9177
|
console.log(
|
|
9086
|
-
|
|
9087
|
-
|
|
9178
|
+
chalk12.gray(" Compose file:"),
|
|
9179
|
+
fs11.existsSync(composeFile) ? chalk12.green("\u2713") : chalk12.red("\u2717")
|
|
9088
9180
|
);
|
|
9089
|
-
console.log(
|
|
9090
|
-
const webEnv =
|
|
9091
|
-
const apiEnv =
|
|
9092
|
-
const dockerEnv =
|
|
9181
|
+
console.log(chalk12.cyan("\n\u{1F510} Environment:"));
|
|
9182
|
+
const webEnv = path17.join(dir, "web/.env");
|
|
9183
|
+
const apiEnv = path17.join(dir, "api/.env");
|
|
9184
|
+
const dockerEnv = path17.join(dir, "docker/.env");
|
|
9093
9185
|
console.log(
|
|
9094
|
-
|
|
9095
|
-
|
|
9186
|
+
chalk12.gray(" Web .env:"),
|
|
9187
|
+
fs11.existsSync(webEnv) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9096
9188
|
);
|
|
9097
9189
|
console.log(
|
|
9098
|
-
|
|
9099
|
-
|
|
9190
|
+
chalk12.gray(" API .env:"),
|
|
9191
|
+
fs11.existsSync(apiEnv) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9100
9192
|
);
|
|
9101
9193
|
console.log(
|
|
9102
|
-
|
|
9103
|
-
|
|
9194
|
+
chalk12.gray(" Docker .env:"),
|
|
9195
|
+
fs11.existsSync(dockerEnv) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9104
9196
|
);
|
|
9105
|
-
if (
|
|
9197
|
+
if (fs11.existsSync(apiEnv)) {
|
|
9106
9198
|
const missingKeys = detectMissingProviderKeys(apiEnv);
|
|
9107
9199
|
if (missingKeys.length > 0) {
|
|
9108
9200
|
console.log(
|
|
9109
|
-
|
|
9110
|
-
|
|
9201
|
+
chalk12.gray(" Provider keys:"),
|
|
9202
|
+
chalk12.yellow(`\u26A0\uFE0F ${missingKeys.length} missing`)
|
|
9111
9203
|
);
|
|
9112
|
-
console.log(
|
|
9204
|
+
console.log(chalk12.gray(" Missing:"), missingKeys.map((k) => chalk12.cyan(k)).join(", "));
|
|
9113
9205
|
} else {
|
|
9114
|
-
console.log(
|
|
9206
|
+
console.log(chalk12.gray(" Provider keys:"), chalk12.green("\u2713 Configured"));
|
|
9115
9207
|
}
|
|
9116
9208
|
}
|
|
9117
|
-
console.log(
|
|
9118
|
-
const generatorsYaml =
|
|
9119
|
-
const storageYaml =
|
|
9209
|
+
console.log(chalk12.cyan("\n\u2699\uFE0F Configuration:"));
|
|
9210
|
+
const generatorsYaml = path17.join(dir, "api/config/generators.yaml");
|
|
9211
|
+
const storageYaml = path17.join(dir, "api/config/storage_config.yaml");
|
|
9120
9212
|
console.log(
|
|
9121
|
-
|
|
9122
|
-
|
|
9213
|
+
chalk12.gray(" generators.yaml:"),
|
|
9214
|
+
fs11.existsSync(generatorsYaml) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9123
9215
|
);
|
|
9124
9216
|
console.log(
|
|
9125
|
-
|
|
9126
|
-
|
|
9217
|
+
chalk12.gray(" storage_config.yaml:"),
|
|
9218
|
+
fs11.existsSync(storageYaml) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9127
9219
|
);
|
|
9128
|
-
const storageDir =
|
|
9220
|
+
const storageDir = path17.join(dir, "data/storage");
|
|
9129
9221
|
console.log(
|
|
9130
|
-
|
|
9131
|
-
|
|
9222
|
+
chalk12.gray(" Storage directory:"),
|
|
9223
|
+
fs11.existsSync(storageDir) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9132
9224
|
);
|
|
9133
9225
|
}
|
|
9134
|
-
console.log(
|
|
9226
|
+
console.log(chalk12.cyan("\n\u{1F4A1} Recommendations:"));
|
|
9135
9227
|
const recommendations = [];
|
|
9136
9228
|
if (!prereqs.node.satisfies) {
|
|
9137
9229
|
recommendations.push("Upgrade Node.js to v20 or higher");
|
|
@@ -9142,18 +9234,18 @@ async function doctor(directory) {
|
|
|
9142
9234
|
recommendations.push("Update Docker to get Compose v2");
|
|
9143
9235
|
}
|
|
9144
9236
|
if (!scaffolded) {
|
|
9145
|
-
recommendations.push("Run " +
|
|
9237
|
+
recommendations.push("Run " + chalk12.cyan("baseboards up") + " to scaffold a project");
|
|
9146
9238
|
}
|
|
9147
9239
|
if (recommendations.length === 0) {
|
|
9148
|
-
console.log(
|
|
9240
|
+
console.log(chalk12.green(" \u2713 Everything looks good!"));
|
|
9149
9241
|
} else {
|
|
9150
|
-
recommendations.forEach((rec) => console.log(
|
|
9242
|
+
recommendations.forEach((rec) => console.log(chalk12.yellow(" \u2022"), rec));
|
|
9151
9243
|
}
|
|
9152
9244
|
console.log();
|
|
9153
9245
|
}
|
|
9154
9246
|
|
|
9155
9247
|
// src/commands/templates.ts
|
|
9156
|
-
import
|
|
9248
|
+
import chalk13 from "chalk";
|
|
9157
9249
|
function formatSize(bytes) {
|
|
9158
9250
|
if (bytes < 1024) {
|
|
9159
9251
|
return `${bytes} B`;
|
|
@@ -9164,22 +9256,22 @@ function formatSize(bytes) {
|
|
|
9164
9256
|
}
|
|
9165
9257
|
}
|
|
9166
9258
|
function displayTemplate(template, isRecommended) {
|
|
9167
|
-
const name =
|
|
9168
|
-
const recommended = isRecommended ?
|
|
9259
|
+
const name = chalk13.bold(template.name);
|
|
9260
|
+
const recommended = isRecommended ? chalk13.cyan(" (recommended)") : "";
|
|
9169
9261
|
console.log(`
|
|
9170
9262
|
${name}${recommended}`);
|
|
9171
9263
|
console.log(` ${template.description}`);
|
|
9172
9264
|
const frameworks = template.frameworks.join(", ");
|
|
9173
|
-
console.log(` ${
|
|
9265
|
+
console.log(` ${chalk13.gray("Frameworks:")} ${frameworks}`);
|
|
9174
9266
|
const features = template.features.join(", ");
|
|
9175
|
-
console.log(` ${
|
|
9267
|
+
console.log(` ${chalk13.gray("Features:")} ${features}`);
|
|
9176
9268
|
const size = formatSize(template.size);
|
|
9177
|
-
console.log(` ${
|
|
9269
|
+
console.log(` ${chalk13.gray("Size:")} ${size}`);
|
|
9178
9270
|
}
|
|
9179
9271
|
async function templates(options) {
|
|
9180
9272
|
try {
|
|
9181
9273
|
if (options.refresh) {
|
|
9182
|
-
console.log(
|
|
9274
|
+
console.log(chalk13.blue("\u{1F504} Clearing cache and refreshing templates...\n"));
|
|
9183
9275
|
await clearCache();
|
|
9184
9276
|
}
|
|
9185
9277
|
const version = options.version || getCliVersion();
|
|
@@ -9189,24 +9281,24 @@ async function templates(options) {
|
|
|
9189
9281
|
} catch (error) {
|
|
9190
9282
|
if (error.message.includes("Failed to fetch")) {
|
|
9191
9283
|
console.error(
|
|
9192
|
-
|
|
9284
|
+
chalk13.red("\n\u274C Network error:"),
|
|
9193
9285
|
"Unable to fetch template list"
|
|
9194
9286
|
);
|
|
9195
9287
|
console.log(
|
|
9196
|
-
|
|
9288
|
+
chalk13.yellow("\n\u{1F4A1} Tip:"),
|
|
9197
9289
|
"Check your internet connection or try again later"
|
|
9198
9290
|
);
|
|
9199
9291
|
process.exit(1);
|
|
9200
9292
|
}
|
|
9201
9293
|
if (error.message.includes("not found")) {
|
|
9202
9294
|
console.error(
|
|
9203
|
-
|
|
9295
|
+
chalk13.red("\n\u274C Version not found:"),
|
|
9204
9296
|
`Version ${version} does not exist`
|
|
9205
9297
|
);
|
|
9206
9298
|
console.log(
|
|
9207
|
-
|
|
9299
|
+
chalk13.yellow("\n\u{1F4A1} Tip:"),
|
|
9208
9300
|
"Check available versions at:",
|
|
9209
|
-
|
|
9301
|
+
chalk13.cyan("https://github.com/weirdfingers/boards/releases")
|
|
9210
9302
|
);
|
|
9211
9303
|
process.exit(1);
|
|
9212
9304
|
}
|
|
@@ -9214,13 +9306,13 @@ async function templates(options) {
|
|
|
9214
9306
|
}
|
|
9215
9307
|
if (!manifest.templates || manifest.templates.length === 0) {
|
|
9216
9308
|
console.log(
|
|
9217
|
-
|
|
9309
|
+
chalk13.yellow("\n\u26A0\uFE0F No templates available for version"),
|
|
9218
9310
|
manifest.version
|
|
9219
9311
|
);
|
|
9220
9312
|
process.exit(0);
|
|
9221
9313
|
}
|
|
9222
9314
|
console.log(
|
|
9223
|
-
|
|
9315
|
+
chalk13.blue.bold(`
|
|
9224
9316
|
\u{1F4E6} Available templates for v${manifest.version}:`)
|
|
9225
9317
|
);
|
|
9226
9318
|
for (const template of manifest.templates) {
|
|
@@ -9229,10 +9321,10 @@ async function templates(options) {
|
|
|
9229
9321
|
}
|
|
9230
9322
|
console.log();
|
|
9231
9323
|
} catch (error) {
|
|
9232
|
-
console.error(
|
|
9324
|
+
console.error(chalk13.red("\n\u274C Error:"), error.message || "Unknown error");
|
|
9233
9325
|
console.error(
|
|
9234
|
-
|
|
9235
|
-
|
|
9326
|
+
chalk13.yellow("\n\u{1F4A1} Try running:"),
|
|
9327
|
+
chalk13.cyan("baseboards doctor")
|
|
9236
9328
|
);
|
|
9237
9329
|
process.exit(1);
|
|
9238
9330
|
}
|
|
@@ -9277,18 +9369,18 @@ try {
|
|
|
9277
9369
|
process.exit(1);
|
|
9278
9370
|
}
|
|
9279
9371
|
const err = error;
|
|
9280
|
-
console.error(
|
|
9372
|
+
console.error(chalk14.red("\n\u274C Error:"), err.message || "Unknown error");
|
|
9281
9373
|
if (err.stderr) {
|
|
9282
|
-
console.error(
|
|
9283
|
-
console.error(
|
|
9374
|
+
console.error(chalk14.gray("\nDetails:"));
|
|
9375
|
+
console.error(chalk14.gray(err.stderr));
|
|
9284
9376
|
}
|
|
9285
9377
|
console.error(
|
|
9286
|
-
|
|
9287
|
-
|
|
9378
|
+
chalk14.yellow("\n\u{1F4A1} Try running:"),
|
|
9379
|
+
chalk14.cyan("baseboards doctor")
|
|
9288
9380
|
);
|
|
9289
9381
|
console.error(
|
|
9290
|
-
|
|
9291
|
-
|
|
9382
|
+
chalk14.yellow("\u{1F4D6} Documentation:"),
|
|
9383
|
+
chalk14.cyan("https://baseboards.dev/docs")
|
|
9292
9384
|
);
|
|
9293
9385
|
process.exit(1);
|
|
9294
9386
|
}
|