@weirdfingers/baseboards 0.9.6 → 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 +560 -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(
|
|
@@ -7900,14 +7988,14 @@ async function ensureEnvFiles(ctx) {
|
|
|
7900
7988
|
/PROJECT_NAME=.*/g,
|
|
7901
7989
|
`PROJECT_NAME=${ctx.name}`
|
|
7902
7990
|
);
|
|
7903
|
-
|
|
7991
|
+
fs6.writeFileSync(dockerEnvPath, dockerEnv);
|
|
7904
7992
|
}
|
|
7905
7993
|
spinner.succeed("Environment configured");
|
|
7906
7994
|
}
|
|
7907
7995
|
async function promptForApiKeys(ctx) {
|
|
7908
|
-
console.log(
|
|
7909
|
-
console.log(
|
|
7910
|
-
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"));
|
|
7911
7999
|
const response = await prompts2([
|
|
7912
8000
|
{
|
|
7913
8001
|
type: "password",
|
|
@@ -7948,8 +8036,8 @@ async function promptForApiKeys(ctx) {
|
|
|
7948
8036
|
apiKeys.OPENAI_API_KEY = response.OPENAI_API_KEY.trim();
|
|
7949
8037
|
}
|
|
7950
8038
|
if (Object.keys(apiKeys).length > 0) {
|
|
7951
|
-
const apiEnvPath =
|
|
7952
|
-
let apiEnv =
|
|
8039
|
+
const apiEnvPath = path6.join(ctx.dir, "api/.env");
|
|
8040
|
+
let apiEnv = fs6.readFileSync(apiEnvPath, "utf-8");
|
|
7953
8041
|
const jsonKeys = JSON.stringify(apiKeys);
|
|
7954
8042
|
if (apiEnv.includes("BOARDS_GENERATOR_API_KEYS=")) {
|
|
7955
8043
|
apiEnv = apiEnv.replace(
|
|
@@ -7965,14 +8053,14 @@ BOARDS_GENERATOR_API_KEYS=${jsonKeys}
|
|
|
7965
8053
|
`
|
|
7966
8054
|
);
|
|
7967
8055
|
}
|
|
7968
|
-
|
|
7969
|
-
console.log(
|
|
8056
|
+
fs6.writeFileSync(apiEnvPath, apiEnv);
|
|
8057
|
+
console.log(chalk3.green("\n\u2705 API keys saved to api/.env"));
|
|
7970
8058
|
console.log(
|
|
7971
|
-
|
|
8059
|
+
chalk3.gray(" You can edit this file anytime to add/update keys\n")
|
|
7972
8060
|
);
|
|
7973
8061
|
} else {
|
|
7974
|
-
console.log(
|
|
7975
|
-
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"));
|
|
7976
8064
|
}
|
|
7977
8065
|
}
|
|
7978
8066
|
function getComposeFiles(ctx) {
|
|
@@ -7994,8 +8082,8 @@ async function startDockerCompose(ctx) {
|
|
|
7994
8082
|
const spinner = ora2("Starting Docker Compose...").start();
|
|
7995
8083
|
const composeFiles = getComposeFiles(ctx);
|
|
7996
8084
|
for (const file of composeFiles) {
|
|
7997
|
-
const filePath =
|
|
7998
|
-
if (!
|
|
8085
|
+
const filePath = path6.join(ctx.dir, file);
|
|
8086
|
+
if (!fs6.existsSync(filePath)) {
|
|
7999
8087
|
spinner.fail(`Compose file not found: ${file}`);
|
|
8000
8088
|
throw new Error(`Compose file not found: ${file}`);
|
|
8001
8089
|
}
|
|
@@ -8008,7 +8096,7 @@ async function startDockerCompose(ctx) {
|
|
|
8008
8096
|
"--remove-orphans"
|
|
8009
8097
|
];
|
|
8010
8098
|
try {
|
|
8011
|
-
await
|
|
8099
|
+
await execa3("docker", composeArgs, {
|
|
8012
8100
|
cwd: ctx.dir,
|
|
8013
8101
|
stdio: "inherit"
|
|
8014
8102
|
});
|
|
@@ -8020,11 +8108,11 @@ async function startDockerCompose(ctx) {
|
|
|
8020
8108
|
}
|
|
8021
8109
|
async function attachToLogs(ctx) {
|
|
8022
8110
|
console.log(
|
|
8023
|
-
|
|
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")
|
|
8024
8112
|
);
|
|
8025
|
-
console.log(
|
|
8113
|
+
console.log(chalk3.gray("Streaming logs... (Press Ctrl+C to stop)\n"));
|
|
8026
8114
|
const composeArgs = [...getComposeBaseArgs(ctx), "logs", "-f"];
|
|
8027
|
-
await
|
|
8115
|
+
await execa3("docker", composeArgs, {
|
|
8028
8116
|
cwd: ctx.dir,
|
|
8029
8117
|
stdio: "inherit"
|
|
8030
8118
|
});
|
|
@@ -8038,7 +8126,7 @@ async function waitForHealthy(ctx) {
|
|
|
8038
8126
|
const maxWaitMs = 12e4;
|
|
8039
8127
|
const checkHealth = async () => {
|
|
8040
8128
|
try {
|
|
8041
|
-
const { stdout } = await
|
|
8129
|
+
const { stdout } = await execa3(
|
|
8042
8130
|
"docker",
|
|
8043
8131
|
[...getComposeBaseArgs(ctx), "ps", "--format", "json"],
|
|
8044
8132
|
{
|
|
@@ -8068,21 +8156,21 @@ async function waitForHealthy(ctx) {
|
|
|
8068
8156
|
} else {
|
|
8069
8157
|
spinner.warn("Services taking longer than expected...");
|
|
8070
8158
|
console.log(
|
|
8071
|
-
|
|
8159
|
+
chalk3.yellow(
|
|
8072
8160
|
"\n\u26A0\uFE0F Health check timeout. Services may still be starting."
|
|
8073
8161
|
)
|
|
8074
8162
|
);
|
|
8075
8163
|
console.log(
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8164
|
+
chalk3.gray(" Run"),
|
|
8165
|
+
chalk3.cyan("baseboards logs"),
|
|
8166
|
+
chalk3.gray("to check progress.")
|
|
8079
8167
|
);
|
|
8080
8168
|
}
|
|
8081
8169
|
}
|
|
8082
8170
|
async function runMigrations(ctx) {
|
|
8083
8171
|
const spinner = ora2("Running database migrations...").start();
|
|
8084
8172
|
try {
|
|
8085
|
-
const { stdout } = await
|
|
8173
|
+
const { stdout } = await execa3(
|
|
8086
8174
|
"docker",
|
|
8087
8175
|
[
|
|
8088
8176
|
...getComposeBaseArgs(ctx),
|
|
@@ -8098,12 +8186,12 @@ async function runMigrations(ctx) {
|
|
|
8098
8186
|
}
|
|
8099
8187
|
);
|
|
8100
8188
|
if (stdout && (stdout.includes("Running upgrade") || process.env.DEBUG)) {
|
|
8101
|
-
console.log(
|
|
8102
|
-
console.log(
|
|
8189
|
+
console.log(chalk3.gray("\n Migration output:"));
|
|
8190
|
+
console.log(chalk3.gray(" " + stdout.split("\n").join("\n ")));
|
|
8103
8191
|
}
|
|
8104
8192
|
spinner.succeed("Database migrations complete");
|
|
8105
8193
|
spinner.start("Restarting API to apply migrations...");
|
|
8106
|
-
await
|
|
8194
|
+
await execa3(
|
|
8107
8195
|
"docker",
|
|
8108
8196
|
[...getComposeBaseArgs(ctx), "restart", "api"],
|
|
8109
8197
|
{
|
|
@@ -8118,42 +8206,42 @@ async function runMigrations(ctx) {
|
|
|
8118
8206
|
const isPasswordError = errorMessage.includes("password authentication failed") || errorMessage.includes("InvalidPasswordError");
|
|
8119
8207
|
if (isPasswordError) {
|
|
8120
8208
|
console.log(
|
|
8121
|
-
|
|
8209
|
+
chalk3.red(
|
|
8122
8210
|
"\n\u274C Database password mismatch - cannot connect to existing database"
|
|
8123
8211
|
)
|
|
8124
8212
|
);
|
|
8125
8213
|
console.log(
|
|
8126
|
-
|
|
8214
|
+
chalk3.yellow(
|
|
8127
8215
|
" Existing database volumes have a different password than the current configuration."
|
|
8128
8216
|
)
|
|
8129
8217
|
);
|
|
8130
|
-
console.log(
|
|
8218
|
+
console.log(chalk3.yellow("\n To fix this, choose one of:"));
|
|
8131
8219
|
console.log(
|
|
8132
|
-
|
|
8220
|
+
chalk3.cyan(" 1. Start fresh (deletes data):") + chalk3.gray(" baseboards down --volumes && baseboards up")
|
|
8133
8221
|
);
|
|
8134
8222
|
console.log(
|
|
8135
|
-
|
|
8223
|
+
chalk3.cyan(" 2. Start fresh automatically:") + chalk3.gray(" baseboards up --fresh")
|
|
8136
8224
|
);
|
|
8137
8225
|
console.log(
|
|
8138
|
-
|
|
8226
|
+
chalk3.gray(
|
|
8139
8227
|
"\n This usually happens when project files were deleted but Docker volumes remain."
|
|
8140
8228
|
)
|
|
8141
8229
|
);
|
|
8142
8230
|
} else {
|
|
8143
8231
|
console.log(
|
|
8144
|
-
|
|
8232
|
+
chalk3.red(
|
|
8145
8233
|
"\n\u274C Database migrations failed"
|
|
8146
8234
|
)
|
|
8147
8235
|
);
|
|
8148
|
-
console.log(
|
|
8149
|
-
console.log(
|
|
8236
|
+
console.log(chalk3.gray("\n Error details:"));
|
|
8237
|
+
console.log(chalk3.gray(" " + errorMessage));
|
|
8150
8238
|
console.log(
|
|
8151
|
-
|
|
8239
|
+
chalk3.yellow(
|
|
8152
8240
|
"\n You can try running migrations manually:"
|
|
8153
8241
|
)
|
|
8154
8242
|
);
|
|
8155
8243
|
console.log(
|
|
8156
|
-
|
|
8244
|
+
chalk3.cyan(" docker compose exec api alembic upgrade head")
|
|
8157
8245
|
);
|
|
8158
8246
|
}
|
|
8159
8247
|
throw new Error("Database migrations failed");
|
|
@@ -8169,84 +8257,87 @@ function getDevCommand(pm) {
|
|
|
8169
8257
|
return commands[pm];
|
|
8170
8258
|
}
|
|
8171
8259
|
function printDefaultSuccessMessage(ctx, hasKeyWarning) {
|
|
8172
|
-
console.log(
|
|
8260
|
+
console.log(chalk3.green.bold("\n\u2705 Baseboards is running!\n"));
|
|
8173
8261
|
console.log(
|
|
8174
|
-
|
|
8175
|
-
|
|
8262
|
+
chalk3.cyan(" Web: "),
|
|
8263
|
+
chalk3.underline(`http://localhost:${ctx.ports.web}`)
|
|
8176
8264
|
);
|
|
8177
8265
|
console.log(
|
|
8178
|
-
|
|
8179
|
-
|
|
8266
|
+
chalk3.cyan(" API: "),
|
|
8267
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}`)
|
|
8180
8268
|
);
|
|
8181
8269
|
console.log(
|
|
8182
|
-
|
|
8183
|
-
|
|
8270
|
+
chalk3.cyan(" GraphQL: "),
|
|
8271
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}/graphql`)
|
|
8184
8272
|
);
|
|
8185
8273
|
if (hasKeyWarning) {
|
|
8186
|
-
console.log(
|
|
8187
|
-
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"));
|
|
8188
8276
|
console.log(
|
|
8189
|
-
|
|
8190
|
-
|
|
8277
|
+
chalk3.gray(" Docs:"),
|
|
8278
|
+
chalk3.cyan("https://baseboards.dev/docs/setup")
|
|
8191
8279
|
);
|
|
8192
8280
|
}
|
|
8193
|
-
console.log(
|
|
8194
|
-
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"));
|
|
8195
8284
|
console.log();
|
|
8196
8285
|
}
|
|
8197
8286
|
function printAppDevSuccessMessage(ctx, hasKeyWarning) {
|
|
8198
|
-
console.log(
|
|
8287
|
+
console.log(chalk3.green.bold("\n\u2705 Backend services are running!\n"));
|
|
8199
8288
|
console.log(
|
|
8200
|
-
|
|
8201
|
-
|
|
8289
|
+
chalk3.cyan(" API: "),
|
|
8290
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}`)
|
|
8202
8291
|
);
|
|
8203
8292
|
console.log(
|
|
8204
|
-
|
|
8205
|
-
|
|
8293
|
+
chalk3.cyan(" GraphQL: "),
|
|
8294
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}/graphql`)
|
|
8206
8295
|
);
|
|
8207
|
-
console.log(
|
|
8208
|
-
const relativeWebPath =
|
|
8296
|
+
console.log(chalk3.cyan("\nTo start the frontend:\n"));
|
|
8297
|
+
const relativeWebPath = path6.relative(process.cwd(), path6.join(ctx.dir, "web"));
|
|
8209
8298
|
const cdCommand = relativeWebPath || "web";
|
|
8210
8299
|
const packageManager = ctx.packageManager || "pnpm";
|
|
8211
8300
|
const devCommand = getDevCommand(packageManager);
|
|
8212
|
-
console.log(
|
|
8213
|
-
console.log(
|
|
8214
|
-
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"));
|
|
8215
8304
|
if (hasKeyWarning) {
|
|
8216
|
-
console.log(
|
|
8217
|
-
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"));
|
|
8218
8307
|
}
|
|
8219
|
-
console.log(
|
|
8220
|
-
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"));
|
|
8221
8311
|
console.log();
|
|
8222
8312
|
}
|
|
8223
8313
|
function printDevPackagesSuccessMessage(ctx, hasKeyWarning) {
|
|
8224
|
-
console.log(
|
|
8225
|
-
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"));
|
|
8226
8316
|
console.log(
|
|
8227
|
-
|
|
8228
|
-
|
|
8317
|
+
chalk3.cyan(" API: "),
|
|
8318
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}`)
|
|
8229
8319
|
);
|
|
8230
8320
|
console.log(
|
|
8231
|
-
|
|
8232
|
-
|
|
8321
|
+
chalk3.cyan(" GraphQL: "),
|
|
8322
|
+
chalk3.underline(`http://localhost:${ctx.ports.api}/graphql`)
|
|
8233
8323
|
);
|
|
8234
|
-
console.log(
|
|
8235
|
-
console.log(
|
|
8236
|
-
console.log(
|
|
8237
|
-
console.log(
|
|
8238
|
-
console.log(
|
|
8239
|
-
console.log(
|
|
8240
|
-
console.log(
|
|
8241
|
-
console.log(
|
|
8242
|
-
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(`
|
|
8243
8333
|
Frontend will be available at http://localhost:3000`));
|
|
8244
8334
|
if (hasKeyWarning) {
|
|
8245
|
-
console.log(
|
|
8246
|
-
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"));
|
|
8247
8337
|
}
|
|
8248
|
-
console.log(
|
|
8249
|
-
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"));
|
|
8250
8341
|
console.log();
|
|
8251
8342
|
}
|
|
8252
8343
|
function printSuccessMessage(ctx, detached, hasKeyWarning) {
|
|
@@ -8260,7 +8351,7 @@ function printSuccessMessage(ctx, detached, hasKeyWarning) {
|
|
|
8260
8351
|
}
|
|
8261
8352
|
async function checkForExistingVolumes() {
|
|
8262
8353
|
try {
|
|
8263
|
-
const { stdout } = await
|
|
8354
|
+
const { stdout } = await execa3("docker", [
|
|
8264
8355
|
"volume",
|
|
8265
8356
|
"ls",
|
|
8266
8357
|
"--format",
|
|
@@ -8277,14 +8368,14 @@ async function cleanupDockerVolumes(ctx) {
|
|
|
8277
8368
|
const spinner = ora2("Cleaning up Docker volumes...").start();
|
|
8278
8369
|
try {
|
|
8279
8370
|
if (ctx.isScaffolded) {
|
|
8280
|
-
await
|
|
8371
|
+
await execa3("docker", [...getComposeBaseArgs(ctx), "down", "-v"], {
|
|
8281
8372
|
cwd: ctx.dir
|
|
8282
8373
|
});
|
|
8283
8374
|
} else {
|
|
8284
8375
|
const volumesToRemove = ["baseboards_db-data", "baseboards_api-storage"];
|
|
8285
8376
|
for (const volumeName of volumesToRemove) {
|
|
8286
8377
|
try {
|
|
8287
|
-
await
|
|
8378
|
+
await execa3("docker", ["volume", "rm", volumeName]);
|
|
8288
8379
|
spinner.text = `Removing volume ${volumeName}...`;
|
|
8289
8380
|
} catch {
|
|
8290
8381
|
}
|
|
@@ -8294,25 +8385,25 @@ async function cleanupDockerVolumes(ctx) {
|
|
|
8294
8385
|
} catch (error) {
|
|
8295
8386
|
spinner.fail("Failed to clean up volumes");
|
|
8296
8387
|
console.log(
|
|
8297
|
-
|
|
8388
|
+
chalk3.yellow(
|
|
8298
8389
|
"\n\u26A0\uFE0F Could not clean up volumes automatically. Try manually:"
|
|
8299
8390
|
)
|
|
8300
8391
|
);
|
|
8301
|
-
console.log(
|
|
8392
|
+
console.log(chalk3.cyan(" docker volume rm baseboards_db-data"));
|
|
8302
8393
|
throw error;
|
|
8303
8394
|
}
|
|
8304
8395
|
}
|
|
8305
8396
|
|
|
8306
8397
|
// src/commands/down.ts
|
|
8307
|
-
import { execa as
|
|
8308
|
-
import
|
|
8309
|
-
import
|
|
8398
|
+
import { execa as execa4 } from "execa";
|
|
8399
|
+
import path7 from "path";
|
|
8400
|
+
import chalk4 from "chalk";
|
|
8310
8401
|
import ora3 from "ora";
|
|
8311
8402
|
async function down(directory, options) {
|
|
8312
|
-
const dir =
|
|
8403
|
+
const dir = path7.resolve(process.cwd(), directory);
|
|
8313
8404
|
if (!isScaffolded(dir)) {
|
|
8314
|
-
console.error(
|
|
8315
|
-
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."));
|
|
8316
8407
|
process.exit(1);
|
|
8317
8408
|
}
|
|
8318
8409
|
const spinner = ora3("Stopping services...").start();
|
|
@@ -8321,12 +8412,12 @@ async function down(directory, options) {
|
|
|
8321
8412
|
args.push("--volumes");
|
|
8322
8413
|
}
|
|
8323
8414
|
try {
|
|
8324
|
-
await
|
|
8415
|
+
await execa4("docker", args, {
|
|
8325
8416
|
cwd: dir
|
|
8326
8417
|
});
|
|
8327
8418
|
spinner.succeed("Services stopped");
|
|
8328
8419
|
if (options.volumes) {
|
|
8329
|
-
console.log(
|
|
8420
|
+
console.log(chalk4.yellow("\u26A0\uFE0F Volumes removed (database data deleted)"));
|
|
8330
8421
|
}
|
|
8331
8422
|
} catch (error) {
|
|
8332
8423
|
spinner.fail("Failed to stop services");
|
|
@@ -8335,14 +8426,14 @@ async function down(directory, options) {
|
|
|
8335
8426
|
}
|
|
8336
8427
|
|
|
8337
8428
|
// src/commands/logs.ts
|
|
8338
|
-
import { execa as
|
|
8339
|
-
import
|
|
8340
|
-
import
|
|
8429
|
+
import { execa as execa5 } from "execa";
|
|
8430
|
+
import path8 from "path";
|
|
8431
|
+
import chalk5 from "chalk";
|
|
8341
8432
|
async function logs(directory, services, options) {
|
|
8342
|
-
const dir =
|
|
8433
|
+
const dir = path8.resolve(process.cwd(), directory);
|
|
8343
8434
|
if (!isScaffolded(dir)) {
|
|
8344
|
-
console.error(
|
|
8345
|
-
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."));
|
|
8346
8437
|
process.exit(1);
|
|
8347
8438
|
}
|
|
8348
8439
|
const args = ["compose", "logs"];
|
|
@@ -8359,7 +8450,7 @@ async function logs(directory, services, options) {
|
|
|
8359
8450
|
args.push(...services);
|
|
8360
8451
|
}
|
|
8361
8452
|
try {
|
|
8362
|
-
await
|
|
8453
|
+
await execa5("docker", args, {
|
|
8363
8454
|
cwd: dir,
|
|
8364
8455
|
stdio: "inherit"
|
|
8365
8456
|
});
|
|
@@ -8371,46 +8462,46 @@ async function logs(directory, services, options) {
|
|
|
8371
8462
|
}
|
|
8372
8463
|
|
|
8373
8464
|
// src/commands/status.ts
|
|
8374
|
-
import { execa as
|
|
8375
|
-
import
|
|
8376
|
-
import
|
|
8465
|
+
import { execa as execa6 } from "execa";
|
|
8466
|
+
import path9 from "path";
|
|
8467
|
+
import chalk6 from "chalk";
|
|
8377
8468
|
async function status(directory) {
|
|
8378
|
-
const dir =
|
|
8469
|
+
const dir = path9.resolve(process.cwd(), directory);
|
|
8379
8470
|
if (!isScaffolded(dir)) {
|
|
8380
|
-
console.error(
|
|
8381
|
-
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."));
|
|
8382
8473
|
process.exit(1);
|
|
8383
8474
|
}
|
|
8384
|
-
console.log(
|
|
8475
|
+
console.log(chalk6.blue.bold("\n\u{1F4CA} Service Status\n"));
|
|
8385
8476
|
try {
|
|
8386
|
-
await
|
|
8477
|
+
await execa6("docker", ["compose", "ps"], {
|
|
8387
8478
|
cwd: dir,
|
|
8388
8479
|
stdio: "inherit"
|
|
8389
8480
|
});
|
|
8390
8481
|
} catch (error) {
|
|
8391
|
-
console.error(
|
|
8482
|
+
console.error(chalk6.red("\n\u274C Failed to get status"));
|
|
8392
8483
|
throw error;
|
|
8393
8484
|
}
|
|
8394
8485
|
}
|
|
8395
8486
|
|
|
8396
8487
|
// src/commands/clean.ts
|
|
8397
|
-
import { execa as
|
|
8398
|
-
import
|
|
8399
|
-
import
|
|
8488
|
+
import { execa as execa7 } from "execa";
|
|
8489
|
+
import path10 from "path";
|
|
8490
|
+
import chalk7 from "chalk";
|
|
8400
8491
|
import ora4 from "ora";
|
|
8401
8492
|
import prompts3 from "prompts";
|
|
8402
8493
|
async function clean(directory, options) {
|
|
8403
|
-
const dir =
|
|
8494
|
+
const dir = path10.resolve(process.cwd(), directory);
|
|
8404
8495
|
if (!isScaffolded(dir)) {
|
|
8405
|
-
console.error(
|
|
8406
|
-
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."));
|
|
8407
8498
|
process.exit(1);
|
|
8408
8499
|
}
|
|
8409
8500
|
if (options.hard) {
|
|
8410
|
-
console.log(
|
|
8411
|
-
console.log(
|
|
8412
|
-
console.log(
|
|
8413
|
-
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"));
|
|
8414
8505
|
const response = await prompts3({
|
|
8415
8506
|
type: "confirm",
|
|
8416
8507
|
name: "confirmed",
|
|
@@ -8418,33 +8509,33 @@ async function clean(directory, options) {
|
|
|
8418
8509
|
initial: false
|
|
8419
8510
|
});
|
|
8420
8511
|
if (!response.confirmed) {
|
|
8421
|
-
console.log(
|
|
8512
|
+
console.log(chalk7.gray("\nCancelled"));
|
|
8422
8513
|
return;
|
|
8423
8514
|
}
|
|
8424
8515
|
}
|
|
8425
8516
|
const spinner = ora4("Cleaning up...").start();
|
|
8426
8517
|
try {
|
|
8427
|
-
await
|
|
8518
|
+
await execa7("docker", ["compose", "down", "--volumes", "--remove-orphans"], {
|
|
8428
8519
|
cwd: dir
|
|
8429
8520
|
});
|
|
8430
8521
|
if (options.hard) {
|
|
8431
8522
|
try {
|
|
8432
|
-
const { stdout } = await
|
|
8523
|
+
const { stdout } = await execa7("docker", ["compose", "images", "-q"], {
|
|
8433
8524
|
cwd: dir
|
|
8434
8525
|
});
|
|
8435
8526
|
const imageIds = stdout.split("\n").filter(Boolean);
|
|
8436
8527
|
if (imageIds.length > 0) {
|
|
8437
|
-
await
|
|
8528
|
+
await execa7("docker", ["rmi", ...imageIds]);
|
|
8438
8529
|
}
|
|
8439
8530
|
} catch (e) {
|
|
8440
8531
|
}
|
|
8441
8532
|
}
|
|
8442
8533
|
spinner.succeed("Cleanup complete");
|
|
8443
8534
|
if (options.hard) {
|
|
8444
|
-
console.log(
|
|
8445
|
-
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."));
|
|
8446
8537
|
} else {
|
|
8447
|
-
console.log(
|
|
8538
|
+
console.log(chalk7.green("\n\u2728 Containers and volumes removed"));
|
|
8448
8539
|
}
|
|
8449
8540
|
} catch (error) {
|
|
8450
8541
|
spinner.fail("Cleanup failed");
|
|
@@ -8453,34 +8544,34 @@ async function clean(directory, options) {
|
|
|
8453
8544
|
}
|
|
8454
8545
|
|
|
8455
8546
|
// src/commands/update.ts
|
|
8456
|
-
import
|
|
8457
|
-
import
|
|
8547
|
+
import path11 from "path";
|
|
8548
|
+
import chalk8 from "chalk";
|
|
8458
8549
|
async function update(directory, options) {
|
|
8459
|
-
const dir =
|
|
8550
|
+
const dir = path11.resolve(process.cwd(), directory);
|
|
8460
8551
|
if (!isScaffolded(dir)) {
|
|
8461
|
-
console.error(
|
|
8462
|
-
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."));
|
|
8463
8554
|
process.exit(1);
|
|
8464
8555
|
}
|
|
8465
|
-
console.log(
|
|
8466
|
-
console.log(
|
|
8467
|
-
console.log(
|
|
8468
|
-
console.log(
|
|
8469
|
-
console.log(
|
|
8470
|
-
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"));
|
|
8471
8562
|
console.log();
|
|
8472
8563
|
}
|
|
8473
8564
|
|
|
8474
8565
|
// src/commands/upgrade.ts
|
|
8475
|
-
import
|
|
8476
|
-
import
|
|
8566
|
+
import path16 from "path";
|
|
8567
|
+
import chalk11 from "chalk";
|
|
8477
8568
|
import prompts4 from "prompts";
|
|
8478
8569
|
|
|
8479
8570
|
// src/utils/mode-detection.ts
|
|
8480
8571
|
import { exec } from "child_process";
|
|
8481
8572
|
import { promisify } from "util";
|
|
8482
|
-
import
|
|
8483
|
-
import
|
|
8573
|
+
import path12 from "path";
|
|
8574
|
+
import fs7 from "fs-extra";
|
|
8484
8575
|
var execAsync2 = promisify(exec);
|
|
8485
8576
|
async function detectProjectMode(projectDir) {
|
|
8486
8577
|
try {
|
|
@@ -8491,15 +8582,15 @@ async function detectProjectMode(projectDir) {
|
|
|
8491
8582
|
}
|
|
8492
8583
|
} catch {
|
|
8493
8584
|
}
|
|
8494
|
-
const modeFile =
|
|
8495
|
-
if (await
|
|
8496
|
-
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();
|
|
8497
8588
|
if (mode === "default" || mode === "app-dev") {
|
|
8498
8589
|
return mode;
|
|
8499
8590
|
}
|
|
8500
8591
|
}
|
|
8501
|
-
const webNodeModules =
|
|
8502
|
-
if (await
|
|
8592
|
+
const webNodeModules = path12.join(projectDir, "web", "node_modules");
|
|
8593
|
+
if (await fs7.pathExists(webNodeModules)) {
|
|
8503
8594
|
return "app-dev";
|
|
8504
8595
|
}
|
|
8505
8596
|
return "default";
|
|
@@ -8510,8 +8601,8 @@ import semver from "semver";
|
|
|
8510
8601
|
|
|
8511
8602
|
// src/utils/compatibility-fetcher.ts
|
|
8512
8603
|
var import_ajv = __toESM(require_ajv(), 1);
|
|
8513
|
-
import
|
|
8514
|
-
import
|
|
8604
|
+
import fs8 from "fs-extra";
|
|
8605
|
+
import path13 from "path";
|
|
8515
8606
|
import os from "os";
|
|
8516
8607
|
import addFormats from "ajv-formats";
|
|
8517
8608
|
|
|
@@ -8574,7 +8665,7 @@ var compatibility_manifest_schema_default = {
|
|
|
8574
8665
|
|
|
8575
8666
|
// src/utils/compatibility-fetcher.ts
|
|
8576
8667
|
var GITHUB_REPO = "weirdfingers/boards";
|
|
8577
|
-
var CACHE_DIR =
|
|
8668
|
+
var CACHE_DIR = path13.join(os.homedir(), ".baseboards", "compatibility");
|
|
8578
8669
|
var ajv = new import_ajv.default({ strict: false });
|
|
8579
8670
|
addFormats(ajv);
|
|
8580
8671
|
var validateManifest = ajv.compile(compatibility_manifest_schema_default);
|
|
@@ -8622,31 +8713,31 @@ function getManifestUrl(version) {
|
|
|
8622
8713
|
}
|
|
8623
8714
|
async function loadFromCache(version) {
|
|
8624
8715
|
const cachePath = getCachePath(version);
|
|
8625
|
-
if (!await
|
|
8716
|
+
if (!await fs8.pathExists(cachePath)) {
|
|
8626
8717
|
return null;
|
|
8627
8718
|
}
|
|
8628
8719
|
try {
|
|
8629
|
-
const content = await
|
|
8720
|
+
const content = await fs8.readFile(cachePath, "utf-8");
|
|
8630
8721
|
const manifest = JSON.parse(content);
|
|
8631
8722
|
if (!validateManifest(manifest)) {
|
|
8632
|
-
await
|
|
8723
|
+
await fs8.remove(cachePath);
|
|
8633
8724
|
return null;
|
|
8634
8725
|
}
|
|
8635
8726
|
return manifest;
|
|
8636
8727
|
} catch (error) {
|
|
8637
|
-
await
|
|
8728
|
+
await fs8.remove(cachePath).catch(() => {
|
|
8638
8729
|
});
|
|
8639
8730
|
return null;
|
|
8640
8731
|
}
|
|
8641
8732
|
}
|
|
8642
8733
|
async function saveToCache(version, manifest) {
|
|
8643
8734
|
const cachePath = getCachePath(version);
|
|
8644
|
-
await
|
|
8645
|
-
await
|
|
8735
|
+
await fs8.ensureDir(CACHE_DIR);
|
|
8736
|
+
await fs8.writeFile(cachePath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
8646
8737
|
}
|
|
8647
8738
|
function getCachePath(version) {
|
|
8648
8739
|
const cleanVersion = version.replace(/^v/, "");
|
|
8649
|
-
return
|
|
8740
|
+
return path13.join(CACHE_DIR, `compatibility-${cleanVersion}.json`);
|
|
8650
8741
|
}
|
|
8651
8742
|
|
|
8652
8743
|
// src/utils/compatibility-checker.ts
|
|
@@ -8698,70 +8789,70 @@ function isVersionAffected(version, affectedRange) {
|
|
|
8698
8789
|
}
|
|
8699
8790
|
|
|
8700
8791
|
// src/commands/upgrade-default.ts
|
|
8701
|
-
import
|
|
8702
|
-
import
|
|
8703
|
-
import
|
|
8704
|
-
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";
|
|
8705
8796
|
import ora5 from "ora";
|
|
8706
8797
|
async function upgradeDefaultMode(projectDir, currentVersion, targetVersion) {
|
|
8707
|
-
console.log(
|
|
8798
|
+
console.log(chalk9.blue(`
|
|
8708
8799
|
\u{1F4E6} Upgrading from v${currentVersion} to v${targetVersion}
|
|
8709
8800
|
`));
|
|
8710
8801
|
try {
|
|
8711
|
-
console.log(
|
|
8802
|
+
console.log(chalk9.gray("\u23F8\uFE0F Stopping services..."));
|
|
8712
8803
|
await execAsync3("docker compose --env-file docker/.env down", { cwd: projectDir });
|
|
8713
|
-
console.log(
|
|
8804
|
+
console.log(chalk9.gray("\u2B07\uFE0F Pulling new backend images..."));
|
|
8714
8805
|
await execAsync3("docker compose --env-file docker/.env pull api worker", { cwd: projectDir });
|
|
8715
|
-
console.log(
|
|
8806
|
+
console.log(chalk9.gray("\u{1F4DD} Updating frontend dependencies..."));
|
|
8716
8807
|
await updateWebPackageJson(projectDir, targetVersion);
|
|
8717
|
-
console.log(
|
|
8808
|
+
console.log(chalk9.gray("\u{1F528} Rebuilding frontend image (this may take a few minutes)..."));
|
|
8718
8809
|
await execAsync3("docker compose --env-file docker/.env build web", { cwd: projectDir });
|
|
8719
|
-
console.log(
|
|
8810
|
+
console.log(chalk9.gray("\u2699\uFE0F Updating configuration..."));
|
|
8720
8811
|
await updateEnvVersion(projectDir, targetVersion);
|
|
8721
|
-
console.log(
|
|
8812
|
+
console.log(chalk9.gray("\u{1F680} Starting services..."));
|
|
8722
8813
|
await execAsync3("docker compose --env-file docker/.env up -d", { cwd: projectDir });
|
|
8723
|
-
console.log(
|
|
8814
|
+
console.log(chalk9.gray("\u{1F3E5} Waiting for services to be healthy..."));
|
|
8724
8815
|
await waitForHealth(projectDir, ["db", "cache", "api", "worker", "web"]);
|
|
8725
|
-
console.log(
|
|
8816
|
+
console.log(chalk9.green(`
|
|
8726
8817
|
\u2705 Successfully upgraded to v${targetVersion}!
|
|
8727
8818
|
`));
|
|
8728
8819
|
printUpgradeSuccess(projectDir, targetVersion);
|
|
8729
8820
|
} catch (error) {
|
|
8730
8821
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
8731
|
-
console.error(
|
|
8822
|
+
console.error(chalk9.red(`
|
|
8732
8823
|
\u274C Upgrade failed: ${errorMessage}
|
|
8733
8824
|
`));
|
|
8734
|
-
console.log(
|
|
8735
|
-
console.log(
|
|
8736
|
-
console.log(
|
|
8737
|
-
console.log(
|
|
8738
|
-
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"));
|
|
8739
8830
|
throw error;
|
|
8740
8831
|
}
|
|
8741
8832
|
}
|
|
8742
8833
|
async function updateWebPackageJson(projectDir, version) {
|
|
8743
|
-
const packageJsonPath =
|
|
8744
|
-
const packageJson2 = await
|
|
8834
|
+
const packageJsonPath = path14.join(projectDir, "web", "package.json");
|
|
8835
|
+
const packageJson2 = await fs9.readJson(packageJsonPath);
|
|
8745
8836
|
if (packageJson2.dependencies && packageJson2.dependencies["@weirdfingers/boards"]) {
|
|
8746
8837
|
packageJson2.dependencies["@weirdfingers/boards"] = version;
|
|
8747
8838
|
}
|
|
8748
|
-
await
|
|
8839
|
+
await fs9.writeJson(packageJsonPath, packageJson2, { spaces: 2 });
|
|
8749
8840
|
}
|
|
8750
8841
|
async function updateEnvVersion(projectDir, version) {
|
|
8751
|
-
const envPath =
|
|
8752
|
-
let content = await
|
|
8842
|
+
const envPath = path14.join(projectDir, "docker", ".env");
|
|
8843
|
+
let content = await fs9.readFile(envPath, "utf-8");
|
|
8753
8844
|
content = content.replace(
|
|
8754
8845
|
/^BACKEND_VERSION=.*/m,
|
|
8755
8846
|
`BACKEND_VERSION=${version}`
|
|
8756
8847
|
);
|
|
8757
|
-
await
|
|
8848
|
+
await fs9.writeFile(envPath, content, "utf-8");
|
|
8758
8849
|
}
|
|
8759
8850
|
async function waitForHealth(projectDir, services) {
|
|
8760
8851
|
const spinner = ora5("Waiting for services to be healthy...").start();
|
|
8761
8852
|
const maxWaitMs = 12e4;
|
|
8762
8853
|
const checkHealth = async () => {
|
|
8763
8854
|
try {
|
|
8764
|
-
const { stdout } = await
|
|
8855
|
+
const { stdout } = await execa8(
|
|
8765
8856
|
"docker",
|
|
8766
8857
|
["compose", "--env-file", "docker/.env", "ps", "--format", "json"],
|
|
8767
8858
|
{
|
|
@@ -8791,106 +8882,106 @@ async function waitForHealth(projectDir, services) {
|
|
|
8791
8882
|
} else {
|
|
8792
8883
|
spinner.warn("Services taking longer than expected...");
|
|
8793
8884
|
console.log(
|
|
8794
|
-
|
|
8885
|
+
chalk9.yellow(
|
|
8795
8886
|
"\n\u26A0\uFE0F Health check timeout. Services may still be starting."
|
|
8796
8887
|
)
|
|
8797
8888
|
);
|
|
8798
8889
|
console.log(
|
|
8799
|
-
|
|
8800
|
-
|
|
8801
|
-
|
|
8890
|
+
chalk9.gray(" Run"),
|
|
8891
|
+
chalk9.cyan("baseboards logs"),
|
|
8892
|
+
chalk9.gray("to check progress.")
|
|
8802
8893
|
);
|
|
8803
8894
|
}
|
|
8804
8895
|
}
|
|
8805
8896
|
function printUpgradeSuccess(projectDir, version) {
|
|
8806
|
-
console.log(
|
|
8807
|
-
console.log(
|
|
8808
|
-
console.log(
|
|
8809
|
-
console.log(
|
|
8810
|
-
console.log(
|
|
8811
|
-
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)}
|
|
8812
8903
|
`));
|
|
8813
8904
|
}
|
|
8814
8905
|
async function execAsync3(command, options) {
|
|
8815
8906
|
const [cmd, ...args] = command.split(" ");
|
|
8816
|
-
return
|
|
8907
|
+
return execa8(cmd, args, options);
|
|
8817
8908
|
}
|
|
8818
8909
|
|
|
8819
8910
|
// src/commands/upgrade-app-dev.ts
|
|
8820
|
-
import
|
|
8821
|
-
import
|
|
8822
|
-
import
|
|
8823
|
-
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";
|
|
8824
8915
|
import ora6 from "ora";
|
|
8825
8916
|
async function upgradeAppDevMode(projectDir, currentVersion, targetVersion) {
|
|
8826
|
-
console.log(
|
|
8917
|
+
console.log(chalk10.blue(`
|
|
8827
8918
|
\u{1F4E6} Upgrading backend from v${currentVersion} to v${targetVersion}
|
|
8828
8919
|
`));
|
|
8829
8920
|
try {
|
|
8830
|
-
console.log(
|
|
8921
|
+
console.log(chalk10.gray("\u23F8\uFE0F Stopping backend services..."));
|
|
8831
8922
|
await execAsync("docker compose --env-file docker/.env down", { cwd: projectDir });
|
|
8832
|
-
console.log(
|
|
8923
|
+
console.log(chalk10.gray("\u2B07\uFE0F Pulling new backend images..."));
|
|
8833
8924
|
await execAsync("docker compose --env-file docker/.env pull api worker", { cwd: projectDir });
|
|
8834
|
-
console.log(
|
|
8925
|
+
console.log(chalk10.gray("\u2699\uFE0F Updating configuration..."));
|
|
8835
8926
|
await updateEnvVersion2(projectDir, targetVersion);
|
|
8836
|
-
console.log(
|
|
8927
|
+
console.log(chalk10.gray("\u{1F680} Starting backend services..."));
|
|
8837
8928
|
await execAsync("docker compose --env-file docker/.env up -d db cache api worker", { cwd: projectDir });
|
|
8838
|
-
console.log(
|
|
8929
|
+
console.log(chalk10.gray("\u{1F3E5} Waiting for backend to be healthy..."));
|
|
8839
8930
|
await waitForHealth2(projectDir, ["db", "cache", "api", "worker"]);
|
|
8840
|
-
console.log(
|
|
8931
|
+
console.log(chalk10.green(`
|
|
8841
8932
|
\u2705 Backend upgraded to v${targetVersion}!
|
|
8842
8933
|
`));
|
|
8843
8934
|
await printAppDevUpgradeInstructions(projectDir, currentVersion, targetVersion);
|
|
8844
8935
|
} catch (error) {
|
|
8845
8936
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
8846
|
-
console.error(
|
|
8937
|
+
console.error(chalk10.red(`
|
|
8847
8938
|
\u274C Upgrade failed: ${errorMessage}
|
|
8848
8939
|
`));
|
|
8849
|
-
console.log(
|
|
8850
|
-
console.log(
|
|
8851
|
-
console.log(
|
|
8852
|
-
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"));
|
|
8853
8944
|
throw error;
|
|
8854
8945
|
}
|
|
8855
8946
|
}
|
|
8856
8947
|
async function updateEnvVersion2(projectDir, version) {
|
|
8857
|
-
const envPath =
|
|
8858
|
-
let content = await
|
|
8948
|
+
const envPath = path15.join(projectDir, "docker", ".env");
|
|
8949
|
+
let content = await fs10.readFile(envPath, "utf-8");
|
|
8859
8950
|
content = content.replace(
|
|
8860
8951
|
/^BACKEND_VERSION=.*/m,
|
|
8861
8952
|
`BACKEND_VERSION=${version}`
|
|
8862
8953
|
);
|
|
8863
|
-
await
|
|
8954
|
+
await fs10.writeFile(envPath, content, "utf-8");
|
|
8864
8955
|
}
|
|
8865
8956
|
async function printAppDevUpgradeInstructions(projectDir, oldVersion, newVersion) {
|
|
8866
|
-
const webDir =
|
|
8957
|
+
const webDir = path15.join(projectDir, "web");
|
|
8867
8958
|
const packageManager = await detectPackageManager(webDir);
|
|
8868
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}`;
|
|
8869
|
-
console.log(
|
|
8870
|
-
console.log(
|
|
8871
|
-
console.log(
|
|
8872
|
-
console.log(
|
|
8873
|
-
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}
|
|
8874
8965
|
`));
|
|
8875
|
-
console.log(
|
|
8876
|
-
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}
|
|
8877
8968
|
`));
|
|
8878
|
-
console.log(
|
|
8879
|
-
console.log(
|
|
8969
|
+
console.log(chalk10.gray(" 4. Restart your dev server:\n"));
|
|
8970
|
+
console.log(chalk10.cyan(` ${packageManager} dev
|
|
8880
8971
|
`));
|
|
8881
8972
|
try {
|
|
8882
8973
|
const { stdout } = await execAsync("git status --porcelain", { cwd: webDir });
|
|
8883
8974
|
if (stdout.trim()) {
|
|
8884
|
-
console.log(
|
|
8885
|
-
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"));
|
|
8886
8977
|
}
|
|
8887
8978
|
} catch (error) {
|
|
8888
|
-
const gitDir =
|
|
8889
|
-
if (!
|
|
8890
|
-
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."));
|
|
8891
8982
|
} else {
|
|
8892
8983
|
console.log(
|
|
8893
|
-
|
|
8984
|
+
chalk10.gray(
|
|
8894
8985
|
" Skipping git status check: git is not available or an error occurred while checking repository status."
|
|
8895
8986
|
)
|
|
8896
8987
|
);
|
|
@@ -8902,7 +8993,7 @@ async function waitForHealth2(projectDir, services) {
|
|
|
8902
8993
|
const maxWaitMs = 12e4;
|
|
8903
8994
|
const checkHealth = async () => {
|
|
8904
8995
|
try {
|
|
8905
|
-
const { stdout } = await
|
|
8996
|
+
const { stdout } = await execa9(
|
|
8906
8997
|
"docker",
|
|
8907
8998
|
["compose", "--env-file", "docker/.env", "ps", "--format", "json"],
|
|
8908
8999
|
{
|
|
@@ -8932,61 +9023,61 @@ async function waitForHealth2(projectDir, services) {
|
|
|
8932
9023
|
} else {
|
|
8933
9024
|
spinner.warn("Services taking longer than expected...");
|
|
8934
9025
|
console.log(
|
|
8935
|
-
|
|
9026
|
+
chalk10.yellow(
|
|
8936
9027
|
"\n\u26A0\uFE0F Health check timeout. Services may still be starting."
|
|
8937
9028
|
)
|
|
8938
9029
|
);
|
|
8939
9030
|
console.log(
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
|
|
9031
|
+
chalk10.gray(" Run"),
|
|
9032
|
+
chalk10.cyan("baseboards logs"),
|
|
9033
|
+
chalk10.gray("to check progress.")
|
|
8943
9034
|
);
|
|
8944
9035
|
}
|
|
8945
9036
|
}
|
|
8946
9037
|
|
|
8947
9038
|
// src/commands/upgrade.ts
|
|
8948
9039
|
async function upgrade(directory, options) {
|
|
8949
|
-
const dir =
|
|
9040
|
+
const dir = path16.resolve(process.cwd(), directory);
|
|
8950
9041
|
if (!isScaffolded(dir)) {
|
|
8951
|
-
console.error(
|
|
8952
|
-
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."));
|
|
8953
9044
|
process.exit(1);
|
|
8954
9045
|
}
|
|
8955
9046
|
const currentVersion = await getCurrentVersion(dir);
|
|
8956
9047
|
if (!currentVersion) {
|
|
8957
|
-
console.error(
|
|
8958
|
-
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"));
|
|
8959
9050
|
process.exit(1);
|
|
8960
9051
|
}
|
|
8961
9052
|
const targetVersion = options.version || await getLatestVersion();
|
|
8962
9053
|
if (currentVersion === targetVersion) {
|
|
8963
|
-
console.log(
|
|
9054
|
+
console.log(chalk11.green(`
|
|
8964
9055
|
\u2705 Already at v${targetVersion}`));
|
|
8965
9056
|
return;
|
|
8966
9057
|
}
|
|
8967
9058
|
const compatCheck = await checkCompatibility(currentVersion, targetVersion);
|
|
8968
9059
|
const mode = await detectProjectMode(dir);
|
|
8969
|
-
console.log(
|
|
8970
|
-
console.log(
|
|
8971
|
-
console.log(
|
|
8972
|
-
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}`));
|
|
8973
9064
|
console.log("");
|
|
8974
9065
|
if (mode === "default") {
|
|
8975
|
-
console.log(
|
|
8976
|
-
console.log(
|
|
8977
|
-
console.log(
|
|
8978
|
-
console.log(
|
|
8979
|
-
console.log(
|
|
8980
|
-
console.log(
|
|
8981
|
-
console.log(
|
|
8982
|
-
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"));
|
|
8983
9074
|
} else {
|
|
8984
|
-
console.log(
|
|
8985
|
-
console.log(
|
|
8986
|
-
console.log(
|
|
8987
|
-
console.log(
|
|
8988
|
-
console.log(
|
|
8989
|
-
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"));
|
|
8990
9081
|
}
|
|
8991
9082
|
console.log("");
|
|
8992
9083
|
if (compatCheck.warnings.length > 0) {
|
|
@@ -8994,18 +9085,18 @@ async function upgrade(directory, options) {
|
|
|
8994
9085
|
console.log("");
|
|
8995
9086
|
}
|
|
8996
9087
|
if (compatCheck.requiredActions.length > 0) {
|
|
8997
|
-
console.log(
|
|
9088
|
+
console.log(chalk11.yellow("\u26A0\uFE0F Required manual actions:"));
|
|
8998
9089
|
compatCheck.requiredActions.forEach((action) => {
|
|
8999
|
-
console.log(
|
|
9090
|
+
console.log(chalk11.gray(` \u2022 ${action}`));
|
|
9000
9091
|
});
|
|
9001
9092
|
console.log("");
|
|
9002
9093
|
}
|
|
9003
9094
|
if (options.dryRun) {
|
|
9004
|
-
console.log(
|
|
9095
|
+
console.log(chalk11.blue("\u{1F50D} Dry run complete - no changes made\n"));
|
|
9005
9096
|
return;
|
|
9006
9097
|
}
|
|
9007
9098
|
if (options.force && compatCheck.breaking) {
|
|
9008
|
-
console.log(
|
|
9099
|
+
console.log(chalk11.yellow("\u26A0\uFE0F --force flag used: skipping confirmation despite breaking changes\n"));
|
|
9009
9100
|
}
|
|
9010
9101
|
if (!options.force && compatCheck.breaking) {
|
|
9011
9102
|
const { proceed } = await prompts4({
|
|
@@ -9015,7 +9106,7 @@ async function upgrade(directory, options) {
|
|
|
9015
9106
|
initial: false
|
|
9016
9107
|
});
|
|
9017
9108
|
if (!proceed) {
|
|
9018
|
-
console.log(
|
|
9109
|
+
console.log(chalk11.gray("\nUpgrade cancelled\n"));
|
|
9019
9110
|
return;
|
|
9020
9111
|
}
|
|
9021
9112
|
}
|
|
@@ -9035,104 +9126,104 @@ async function getLatestVersion() {
|
|
|
9035
9126
|
}
|
|
9036
9127
|
|
|
9037
9128
|
// src/commands/doctor.ts
|
|
9038
|
-
import
|
|
9039
|
-
import
|
|
9040
|
-
import
|
|
9129
|
+
import path17 from "path";
|
|
9130
|
+
import fs11 from "fs-extra";
|
|
9131
|
+
import chalk12 from "chalk";
|
|
9041
9132
|
async function doctor(directory) {
|
|
9042
|
-
const dir =
|
|
9043
|
-
console.log(
|
|
9044
|
-
console.log(
|
|
9045
|
-
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:"));
|
|
9046
9137
|
const prereqs = await checkPrerequisites();
|
|
9047
9138
|
console.log(
|
|
9048
|
-
|
|
9049
|
-
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")
|
|
9050
9141
|
);
|
|
9051
9142
|
console.log(
|
|
9052
|
-
|
|
9053
|
-
prereqs.docker.installed ?
|
|
9143
|
+
chalk12.gray(" Docker:"),
|
|
9144
|
+
prereqs.docker.installed ? chalk12.green(`\u2713 v${prereqs.docker.version}`) : chalk12.red("\u2717 Not installed")
|
|
9054
9145
|
);
|
|
9055
9146
|
if (prereqs.docker.composeVersion) {
|
|
9056
9147
|
console.log(
|
|
9057
|
-
|
|
9058
|
-
|
|
9148
|
+
chalk12.gray(" Docker Compose:"),
|
|
9149
|
+
chalk12.green(`\u2713 v${prereqs.docker.composeVersion}`)
|
|
9059
9150
|
);
|
|
9060
9151
|
} else if (prereqs.docker.installed) {
|
|
9061
|
-
console.log(
|
|
9152
|
+
console.log(chalk12.gray(" Docker Compose:"), chalk12.red("\u2717 Not available"));
|
|
9062
9153
|
}
|
|
9063
|
-
console.log(
|
|
9154
|
+
console.log(chalk12.gray(" Platform:"), prereqs.platform.name);
|
|
9064
9155
|
if (prereqs.platform.isWSL) {
|
|
9065
|
-
console.log(
|
|
9156
|
+
console.log(chalk12.gray(" WSL:"), chalk12.blue("\u2713 Detected"));
|
|
9066
9157
|
}
|
|
9067
|
-
console.log(
|
|
9158
|
+
console.log(chalk12.cyan("\n\u{1F4C2} Project:"));
|
|
9068
9159
|
const scaffolded = isScaffolded(dir);
|
|
9069
9160
|
console.log(
|
|
9070
|
-
|
|
9071
|
-
scaffolded ?
|
|
9161
|
+
chalk12.gray(" Scaffolded:"),
|
|
9162
|
+
scaffolded ? chalk12.green("\u2713 Yes") : chalk12.yellow("\u2717 No")
|
|
9072
9163
|
);
|
|
9073
9164
|
if (scaffolded) {
|
|
9074
|
-
console.log(
|
|
9075
|
-
const webPkg =
|
|
9076
|
-
const apiPkg =
|
|
9077
|
-
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");
|
|
9078
9169
|
console.log(
|
|
9079
|
-
|
|
9080
|
-
|
|
9170
|
+
chalk12.gray(" Web package:"),
|
|
9171
|
+
fs11.existsSync(webPkg) ? chalk12.green("\u2713") : chalk12.red("\u2717")
|
|
9081
9172
|
);
|
|
9082
9173
|
console.log(
|
|
9083
|
-
|
|
9084
|
-
|
|
9174
|
+
chalk12.gray(" API package:"),
|
|
9175
|
+
fs11.existsSync(apiPkg) ? chalk12.green("\u2713") : chalk12.red("\u2717")
|
|
9085
9176
|
);
|
|
9086
9177
|
console.log(
|
|
9087
|
-
|
|
9088
|
-
|
|
9178
|
+
chalk12.gray(" Compose file:"),
|
|
9179
|
+
fs11.existsSync(composeFile) ? chalk12.green("\u2713") : chalk12.red("\u2717")
|
|
9089
9180
|
);
|
|
9090
|
-
console.log(
|
|
9091
|
-
const webEnv =
|
|
9092
|
-
const apiEnv =
|
|
9093
|
-
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");
|
|
9094
9185
|
console.log(
|
|
9095
|
-
|
|
9096
|
-
|
|
9186
|
+
chalk12.gray(" Web .env:"),
|
|
9187
|
+
fs11.existsSync(webEnv) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9097
9188
|
);
|
|
9098
9189
|
console.log(
|
|
9099
|
-
|
|
9100
|
-
|
|
9190
|
+
chalk12.gray(" API .env:"),
|
|
9191
|
+
fs11.existsSync(apiEnv) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9101
9192
|
);
|
|
9102
9193
|
console.log(
|
|
9103
|
-
|
|
9104
|
-
|
|
9194
|
+
chalk12.gray(" Docker .env:"),
|
|
9195
|
+
fs11.existsSync(dockerEnv) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9105
9196
|
);
|
|
9106
|
-
if (
|
|
9197
|
+
if (fs11.existsSync(apiEnv)) {
|
|
9107
9198
|
const missingKeys = detectMissingProviderKeys(apiEnv);
|
|
9108
9199
|
if (missingKeys.length > 0) {
|
|
9109
9200
|
console.log(
|
|
9110
|
-
|
|
9111
|
-
|
|
9201
|
+
chalk12.gray(" Provider keys:"),
|
|
9202
|
+
chalk12.yellow(`\u26A0\uFE0F ${missingKeys.length} missing`)
|
|
9112
9203
|
);
|
|
9113
|
-
console.log(
|
|
9204
|
+
console.log(chalk12.gray(" Missing:"), missingKeys.map((k) => chalk12.cyan(k)).join(", "));
|
|
9114
9205
|
} else {
|
|
9115
|
-
console.log(
|
|
9206
|
+
console.log(chalk12.gray(" Provider keys:"), chalk12.green("\u2713 Configured"));
|
|
9116
9207
|
}
|
|
9117
9208
|
}
|
|
9118
|
-
console.log(
|
|
9119
|
-
const generatorsYaml =
|
|
9120
|
-
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");
|
|
9121
9212
|
console.log(
|
|
9122
|
-
|
|
9123
|
-
|
|
9213
|
+
chalk12.gray(" generators.yaml:"),
|
|
9214
|
+
fs11.existsSync(generatorsYaml) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9124
9215
|
);
|
|
9125
9216
|
console.log(
|
|
9126
|
-
|
|
9127
|
-
|
|
9217
|
+
chalk12.gray(" storage_config.yaml:"),
|
|
9218
|
+
fs11.existsSync(storageYaml) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9128
9219
|
);
|
|
9129
|
-
const storageDir =
|
|
9220
|
+
const storageDir = path17.join(dir, "data/storage");
|
|
9130
9221
|
console.log(
|
|
9131
|
-
|
|
9132
|
-
|
|
9222
|
+
chalk12.gray(" Storage directory:"),
|
|
9223
|
+
fs11.existsSync(storageDir) ? chalk12.green("\u2713") : chalk12.yellow("\u2717 Missing")
|
|
9133
9224
|
);
|
|
9134
9225
|
}
|
|
9135
|
-
console.log(
|
|
9226
|
+
console.log(chalk12.cyan("\n\u{1F4A1} Recommendations:"));
|
|
9136
9227
|
const recommendations = [];
|
|
9137
9228
|
if (!prereqs.node.satisfies) {
|
|
9138
9229
|
recommendations.push("Upgrade Node.js to v20 or higher");
|
|
@@ -9143,18 +9234,18 @@ async function doctor(directory) {
|
|
|
9143
9234
|
recommendations.push("Update Docker to get Compose v2");
|
|
9144
9235
|
}
|
|
9145
9236
|
if (!scaffolded) {
|
|
9146
|
-
recommendations.push("Run " +
|
|
9237
|
+
recommendations.push("Run " + chalk12.cyan("baseboards up") + " to scaffold a project");
|
|
9147
9238
|
}
|
|
9148
9239
|
if (recommendations.length === 0) {
|
|
9149
|
-
console.log(
|
|
9240
|
+
console.log(chalk12.green(" \u2713 Everything looks good!"));
|
|
9150
9241
|
} else {
|
|
9151
|
-
recommendations.forEach((rec) => console.log(
|
|
9242
|
+
recommendations.forEach((rec) => console.log(chalk12.yellow(" \u2022"), rec));
|
|
9152
9243
|
}
|
|
9153
9244
|
console.log();
|
|
9154
9245
|
}
|
|
9155
9246
|
|
|
9156
9247
|
// src/commands/templates.ts
|
|
9157
|
-
import
|
|
9248
|
+
import chalk13 from "chalk";
|
|
9158
9249
|
function formatSize(bytes) {
|
|
9159
9250
|
if (bytes < 1024) {
|
|
9160
9251
|
return `${bytes} B`;
|
|
@@ -9165,22 +9256,22 @@ function formatSize(bytes) {
|
|
|
9165
9256
|
}
|
|
9166
9257
|
}
|
|
9167
9258
|
function displayTemplate(template, isRecommended) {
|
|
9168
|
-
const name =
|
|
9169
|
-
const recommended = isRecommended ?
|
|
9259
|
+
const name = chalk13.bold(template.name);
|
|
9260
|
+
const recommended = isRecommended ? chalk13.cyan(" (recommended)") : "";
|
|
9170
9261
|
console.log(`
|
|
9171
9262
|
${name}${recommended}`);
|
|
9172
9263
|
console.log(` ${template.description}`);
|
|
9173
9264
|
const frameworks = template.frameworks.join(", ");
|
|
9174
|
-
console.log(` ${
|
|
9265
|
+
console.log(` ${chalk13.gray("Frameworks:")} ${frameworks}`);
|
|
9175
9266
|
const features = template.features.join(", ");
|
|
9176
|
-
console.log(` ${
|
|
9267
|
+
console.log(` ${chalk13.gray("Features:")} ${features}`);
|
|
9177
9268
|
const size = formatSize(template.size);
|
|
9178
|
-
console.log(` ${
|
|
9269
|
+
console.log(` ${chalk13.gray("Size:")} ${size}`);
|
|
9179
9270
|
}
|
|
9180
9271
|
async function templates(options) {
|
|
9181
9272
|
try {
|
|
9182
9273
|
if (options.refresh) {
|
|
9183
|
-
console.log(
|
|
9274
|
+
console.log(chalk13.blue("\u{1F504} Clearing cache and refreshing templates...\n"));
|
|
9184
9275
|
await clearCache();
|
|
9185
9276
|
}
|
|
9186
9277
|
const version = options.version || getCliVersion();
|
|
@@ -9190,24 +9281,24 @@ async function templates(options) {
|
|
|
9190
9281
|
} catch (error) {
|
|
9191
9282
|
if (error.message.includes("Failed to fetch")) {
|
|
9192
9283
|
console.error(
|
|
9193
|
-
|
|
9284
|
+
chalk13.red("\n\u274C Network error:"),
|
|
9194
9285
|
"Unable to fetch template list"
|
|
9195
9286
|
);
|
|
9196
9287
|
console.log(
|
|
9197
|
-
|
|
9288
|
+
chalk13.yellow("\n\u{1F4A1} Tip:"),
|
|
9198
9289
|
"Check your internet connection or try again later"
|
|
9199
9290
|
);
|
|
9200
9291
|
process.exit(1);
|
|
9201
9292
|
}
|
|
9202
9293
|
if (error.message.includes("not found")) {
|
|
9203
9294
|
console.error(
|
|
9204
|
-
|
|
9295
|
+
chalk13.red("\n\u274C Version not found:"),
|
|
9205
9296
|
`Version ${version} does not exist`
|
|
9206
9297
|
);
|
|
9207
9298
|
console.log(
|
|
9208
|
-
|
|
9299
|
+
chalk13.yellow("\n\u{1F4A1} Tip:"),
|
|
9209
9300
|
"Check available versions at:",
|
|
9210
|
-
|
|
9301
|
+
chalk13.cyan("https://github.com/weirdfingers/boards/releases")
|
|
9211
9302
|
);
|
|
9212
9303
|
process.exit(1);
|
|
9213
9304
|
}
|
|
@@ -9215,13 +9306,13 @@ async function templates(options) {
|
|
|
9215
9306
|
}
|
|
9216
9307
|
if (!manifest.templates || manifest.templates.length === 0) {
|
|
9217
9308
|
console.log(
|
|
9218
|
-
|
|
9309
|
+
chalk13.yellow("\n\u26A0\uFE0F No templates available for version"),
|
|
9219
9310
|
manifest.version
|
|
9220
9311
|
);
|
|
9221
9312
|
process.exit(0);
|
|
9222
9313
|
}
|
|
9223
9314
|
console.log(
|
|
9224
|
-
|
|
9315
|
+
chalk13.blue.bold(`
|
|
9225
9316
|
\u{1F4E6} Available templates for v${manifest.version}:`)
|
|
9226
9317
|
);
|
|
9227
9318
|
for (const template of manifest.templates) {
|
|
@@ -9230,10 +9321,10 @@ async function templates(options) {
|
|
|
9230
9321
|
}
|
|
9231
9322
|
console.log();
|
|
9232
9323
|
} catch (error) {
|
|
9233
|
-
console.error(
|
|
9324
|
+
console.error(chalk13.red("\n\u274C Error:"), error.message || "Unknown error");
|
|
9234
9325
|
console.error(
|
|
9235
|
-
|
|
9236
|
-
|
|
9326
|
+
chalk13.yellow("\n\u{1F4A1} Try running:"),
|
|
9327
|
+
chalk13.cyan("baseboards doctor")
|
|
9237
9328
|
);
|
|
9238
9329
|
process.exit(1);
|
|
9239
9330
|
}
|
|
@@ -9278,18 +9369,18 @@ try {
|
|
|
9278
9369
|
process.exit(1);
|
|
9279
9370
|
}
|
|
9280
9371
|
const err = error;
|
|
9281
|
-
console.error(
|
|
9372
|
+
console.error(chalk14.red("\n\u274C Error:"), err.message || "Unknown error");
|
|
9282
9373
|
if (err.stderr) {
|
|
9283
|
-
console.error(
|
|
9284
|
-
console.error(
|
|
9374
|
+
console.error(chalk14.gray("\nDetails:"));
|
|
9375
|
+
console.error(chalk14.gray(err.stderr));
|
|
9285
9376
|
}
|
|
9286
9377
|
console.error(
|
|
9287
|
-
|
|
9288
|
-
|
|
9378
|
+
chalk14.yellow("\n\u{1F4A1} Try running:"),
|
|
9379
|
+
chalk14.cyan("baseboards doctor")
|
|
9289
9380
|
);
|
|
9290
9381
|
console.error(
|
|
9291
|
-
|
|
9292
|
-
|
|
9382
|
+
chalk14.yellow("\u{1F4D6} Documentation:"),
|
|
9383
|
+
chalk14.cyan("https://baseboards.dev/docs")
|
|
9293
9384
|
);
|
|
9294
9385
|
process.exit(1);
|
|
9295
9386
|
}
|