# Set shell for commands set shell := ["bash", "-c"] project_root := justfile_directory() # Load environment variables from .env file if it exists set dotenv-load := true [doc("Show available recipes")] default: @just --list # ============================================================================= # LAMINA LAYER BUILDS # ============================================================================= lamina_root := justfile_directory() + "/../lamina" libre_forge_root := justfile_directory() + "/../workspaces/libre-forge" lian_build_root := justfile_directory() + "/../lian-build" secrets_base := justfile_directory() + "/../workspaces/libre-daoshi" rustelo_root := justfile_directory() + "/{{RUSTELO_ROOT}}" strops_root := justfile_directory() + "/../stratumiops" # Build and push: no arg or "website" → build this project via fleet; layer name → delegate to lamina # Pass log=/path/file.log to capture output to a file instead of printing to screen. build-push-remote layer="website" log="": #!/usr/bin/env nu if "{{ layer }}" != "website" { just -f "{{ lamina_root }}/justfile" build-push-remote {{ layer }} return } let forge = "{{ libre_forge_root }}" let kage = ($forge | path join "infra/control-plane/.kage") let sc_file = ($forge | path join "infra/control-plane/secrets/sccache.sops.yaml") let nk_file = ($forge | path join "infra/control-plane/secrets/nkeys.sops.yaml") let handler = ($forge | path join "scripts/provision-relay.nu") for p in [$kage, $sc_file, $nk_file] { if not ($p | path exists) { error make { msg: $"missing: ($p)" } } } let sc_raw = (with-env { SOPS_AGE_KEY_FILE: $kage } { do { ^sops --decrypt --output-type json $sc_file } | complete }) if $sc_raw.exit_code != 0 { error make { msg: $"sops sccache: ($sc_raw.stderr | str trim)" } } let sc = ($sc_raw.stdout | from json) let nk_raw = (with-env { SOPS_AGE_KEY_FILE: $kage } { do { ^sops --decrypt --extract '["forge_control_seed"]' $nk_file } | complete }) if $nk_raw.exit_code != 0 { error make { msg: $"sops nkeys: ($nk_raw.stderr | str trim)" } } let nk_seed = ($nk_raw.stdout | str trim) let image_tag = (open "{{ justfile_directory() }}/Cargo.toml" | get workspace.package.version) let log_file = if ("{{ log }}" != "") { "{{ log }}" } else { null } if $log_file != null { print $" lian-build log: ($log_file)" } let ctx = (^mktemp -d | str trim) print $" assembling context: ($ctx)" ^rsync -a --delete "--exclude=.git/" "--exclude=target/" "--exclude=node_modules/" "--exclude=.coder/" "{{ justfile_directory() }}/" $"($ctx)/" ^rsync -a --delete "--exclude=.git/" "--exclude=target/" "{{ rustelo_root }}/" $"($ctx)/rustelo/" if ("{{ strops_root }}" | path exists) { ^rsync -a --delete "--exclude=.git/" "--exclude=target/" "{{ strops_root }}/" $"($ctx)/stratumiops/" } # Write version-patched project.ncl into lian_build_root so Nickel finds it by logical name. # build_directives.ncl does `import "jpl-project.ncl"` — resolved via LIAN_BUILD_NICKEL_IMPORT_PATH # which already points to lian_build_root. No path changes needed; file is deleted on exit. let proj_override = $"{{ lian_build_root }}/jpl-project.ncl" open "{{ justfile_directory() }}/provisioning/project.ncl" | str replace 'image_tag = "latest"' $'image_tag = "($image_tag)"' | save -f $proj_override let dir_raw = (do { ^nickel export --import-path "{{ lian_build_root }}" "{{ justfile_directory() }}/lian-build/build_directives.ncl" } | complete) if $dir_raw.exit_code != 0 { rm -f $proj_override; error make { msg: $"nickel export directives: ($dir_raw.stderr | str trim)" } } let fleet_nats_url = ($dir_raw.stdout | from json | get adapter.nats_url) # nats CLI requires the NKey seed as a file (--nkey), not as $NATS_SEED string. let nkey_file = (^mktemp | str trim) $nk_seed | save -f $nkey_file let relay_job = (job spawn --description "provision-relay" { ^nats --server $fleet_nats_url --nkey $nkey_file reply "fleet.libre-forge.ops.provision.>" --command $"nu ($handler)" }) print $" provision-relay: job ($relay_job)" print $" daemon logs: ssh libre-daoshi-0 'k0s kubectl -n fleet-system logs -l app=fleet-daemon -f'" let daoshi_kage = ("{{ secrets_base }}" | path join "infra/libre-daoshi/.kage") try { with-env { AWS_ACCESS_KEY_ID: $sc.access_key_id, AWS_SECRET_ACCESS_KEY: $sc.secret_access_key, NATS_NKEY_SEED: $nk_seed, LIAN_BUILD_NICKEL_IMPORT_PATH: "{{ lian_build_root }}", SOPS_AGE_KEY_FILE: $daoshi_kage, } { if $log_file != null { ^lian-build build --directives "{{ justfile_directory() }}/lian-build/build_directives.ncl" --context $ctx --secrets-base "{{ secrets_base }}" o+e> $log_file } else { ^lian-build build --directives "{{ justfile_directory() }}/lian-build/build_directives.ncl" --context $ctx --secrets-base "{{ secrets_base }}" } } } catch { |e| job kill $relay_job rm -f $nkey_file $proj_override rm -rf $ctx let hint = if $log_file != null { $" — see ($log_file)" } else { "" } error make { msg: $"lian-build failed($hint)\n($e.msg)" } } job kill $relay_job rm -f $nkey_file $proj_override rm -rf $ctx # Build server binary only: WASM is compiled locally then sent as part of the context. # wasm= override the WASM artifacts dir (default: target/site/). # If absent and no override is given, builds WASM locally first. # log= capture lian-build output to a file instead of printing to screen. build-push-server wasm="" log="": #!/usr/bin/env nu let forge = "{{ libre_forge_root }}" let kage = ($forge | path join "infra/control-plane/.kage") let sc_file = ($forge | path join "infra/control-plane/secrets/sccache.sops.yaml") let nk_file = ($forge | path join "infra/control-plane/secrets/nkeys.sops.yaml") let handler = ($forge | path join "scripts/provision-relay.nu") for p in [$kage, $sc_file, $nk_file] { if not ($p | path exists) { error make { msg: $"missing: ($p)" } } } let sc_raw = (with-env { SOPS_AGE_KEY_FILE: $kage } { do { ^sops --decrypt --output-type json $sc_file } | complete }) if $sc_raw.exit_code != 0 { error make { msg: $"sops sccache: ($sc_raw.stderr | str trim)" } } let sc = ($sc_raw.stdout | from json) let nk_raw = (with-env { SOPS_AGE_KEY_FILE: $kage } { do { ^sops --decrypt --extract '["forge_control_seed"]' $nk_file } | complete }) if $nk_raw.exit_code != 0 { error make { msg: $"sops nkeys: ($nk_raw.stderr | str trim)" } } let nk_seed = ($nk_raw.stdout | str trim) let image_tag = (open "{{ justfile_directory() }}/Cargo.toml" | get workspace.package.version) let wasm_site = if ("{{ wasm }}" != "") { "{{ wasm }}" } else { let target_dir = ( $env.CARGO_TARGET_DIR? | default ( let cfg = "{{ justfile_directory() }}/.cargo/config.toml" if ($cfg | path exists) { (open $cfg).build?."target-dir"? | default "{{ justfile_directory() }}/target" } else { "{{ justfile_directory() }}/target" } ) ) $target_dir | path join "site" } if not ($wasm_site | path exists) { print " building WASM frontend locally (no artifacts at ($wasm_site))..." with-env { SITE_CONFIG_PATH: "{{ justfile_directory() }}/site/config/index.ncl", NICKEL_IMPORT_PATH: $"{{ rustelo_root }}/resources/nickel:{{ justfile_directory() }}/site/config", } { ^cargo leptos build --frontend-only --release } } let log_file = if ("{{ log }}" != "") { "{{ log }}" } else { null } if $log_file != null { print $" lian-build log: ($log_file)" } let ctx = (^mktemp -d | str trim) print $" assembling context: ($ctx)" ^rsync -a --delete "--exclude=.git/" "--exclude=target/" "--exclude=node_modules/" "--exclude=.coder/" "{{ justfile_directory() }}/" $"($ctx)/" ^rsync -a --delete "--exclude=.git/" "--exclude=target/" "{{ rustelo_root }}/" $"($ctx)/rustelo/" if ("{{ strops_root }}" | path exists) { ^rsync -a --delete "--exclude=.git/" "--exclude=target/" "{{ strops_root }}/" $"($ctx)/stratumiops/" } # Inject WASM artifacts into context as wasm-site/ ^rsync -a --delete $"($wasm_site)/" $"($ctx)/wasm-site/" print $" wasm-site: ($wasm_site)" # Write version-patched project.ncl into lian_build_root — same approach as build-push-remote. let proj_override = $"{{ lian_build_root }}/jpl-project.ncl" open "{{ justfile_directory() }}/provisioning/project.ncl" | str replace 'image_tag = "latest"' $'image_tag = "($image_tag)"' | save -f $proj_override let dir_raw = (do { ^nickel export --import-path "{{ lian_build_root }}" "{{ justfile_directory() }}/lian-build/build_directives_server.ncl" } | complete) if $dir_raw.exit_code != 0 { rm -f $proj_override; error make { msg: $"nickel export directives: ($dir_raw.stderr | str trim)" } } let fleet_nats_url = ($dir_raw.stdout | from json | get adapter.nats_url) let nkey_file = (^mktemp | str trim) $nk_seed | save -f $nkey_file let relay_job = (job spawn --description "provision-relay" { ^nats --server $fleet_nats_url --nkey $nkey_file reply "fleet.libre-forge.ops.provision.>" --command $"nu ($handler)" }) print $" provision-relay: job ($relay_job)" print $" daemon logs: ssh libre-daoshi-0 'k0s kubectl -n fleet-system logs -l app=fleet-daemon -f'" let daoshi_kage = ("{{ secrets_base }}" | path join "infra/libre-daoshi/.kage") try { with-env { AWS_ACCESS_KEY_ID: $sc.access_key_id, AWS_SECRET_ACCESS_KEY: $sc.secret_access_key, NATS_NKEY_SEED: $nk_seed, LIAN_BUILD_NICKEL_IMPORT_PATH: "{{ lian_build_root }}", SOPS_AGE_KEY_FILE: $daoshi_kage, } { if $log_file != null { ^lian-build build --directives "{{ justfile_directory() }}/lian-build/build_directives_server.ncl" --context $ctx --secrets-base "{{ secrets_base }}" o+e> $log_file } else { ^lian-build build --directives "{{ justfile_directory() }}/lian-build/build_directives_server.ncl" --context $ctx --secrets-base "{{ secrets_base }}" } } } catch { |e| job kill $relay_job rm -f $nkey_file $proj_override rm -rf $ctx let hint = if $log_file != null { $" — see ($log_file)" } else { "" } error make { msg: $"lian-build failed($hint)\n($e.msg)" } } job kill $relay_job rm -f $nkey_file $proj_override rm -rf $ctx libre_wuji_root := justfile_directory() + "/../workspaces/secrets-base" # Register this project into a workspace repo, injecting the current Cargo.toml version as image_tag. # workspace= override the target workspace root (default: secrets-base sibling). [doc("Write versioned appserv/builds stubs into the workspace repo")] register workspace="" workspace_name="secrets-base": #!/usr/bin/env nu let image_tag = (open "{{ justfile_directory() }}/Cargo.toml" | get workspace.package.version) let ws = if ("{{ workspace }}" | is-not-empty) { "{{ workspace }}" } else { "{{ libre_wuji_root }}" } if not ($ws | path exists) { error make { msg: $"workspace not found: ($ws)" } } print $"[register] image_tag: ($image_tag), workspace: ($ws)" ^nu "{{ justfile_directory() }}/provisioning/register.nu" --workspace $ws --workspace-name "{{ workspace_name }}" --image-tag $image_tag # ============================================================================= # MODULE IMPORTS # ============================================================================= mod dev "justfiles/dev.just" mod build "justfiles/build.just" mod database "justfiles/database.just" mod docs "justfiles/docs.just" mod test "justfiles/test.just" mod utils "justfiles/utils.just" mod tools "justfiles/tools.just" mod helptext "justfiles/helptext.just" mod cache "justfiles/cache.just" mod ui "justfiles/ui.just" # ============================================================================= # ALIASES # ============================================================================= alias a := list-alias alias b := build-dev alias bp := build-prod alias s := dev-full alias sp := serve-prod alias sc := serve-cms alias cb := content-build alias oa := dev::organize-artifacts alias sbl := server-browser-logs alias bl := browser-logs alias t := test-run alias d := start alias df := dev-fast alias dc := dev-coordinated alias dm := dev-minimal alias ba := build-artifacts alias bs := build-status alias ca := clean-build-artifacts alias cs := cache::cs alias cc := cache::cache-clean alias cca := cache::cache-clean # alias dev := start # Conflicts with module name # alias h := help # Defined as recipe below alias ha := help-all alias o := overview alias c := cross-build alias pt := page-tester alias pr := pages-report alias pn := page-new alias sh := show # Tools aliases alias ta := build-tools-analyze alias tm := build-tools-manage alias tg := build-tools-generate-page alias ts := build-tools-status # Navigation Testing aliases alias nts := dev::with-nav-test # Nav Test Start alias nt := dev::nav-test-route # Nav Test route alias ns := dev::nav-test-sequence # Nav test Sequence alias nv := dev::nav-test-validate # Nav Validate alias nb := dev::nav-test-bench # Nav Bench alias na := dev::nav-test-all # Nav All tests alias nc := dev::nav-quick-check # Nav Check (CI/CD) alias nd := dev::nav-dashboard # Nav Dashboard alias nh := dev::nav-help # Nav Help # Quick nav test aliases for common routes alias nt-home := nav-test-home # Test home route alias nt-services := nav-test-services # Test services route alias nt-contact := nav-test-contact # Test contact route alias nt-blog := nav-test-blog # Test blog route alias nt-es := nav-test-es # Test Spanish home alias nt-contactar := nav-test-contactar # Test Spanish contact # UI Management aliases alias routes := ui::routes-list alias pages := ui::pages-list alias components := ui::components-list # ============================================================================= # CORE COMMANDS (Backward Compatibility & Common Tasks) # ============================================================================= list-alias: @echo "🔗 List of aliases:" @cat {{justfile()}} | grep "^alias" | sed 's/^alias / /g' # Show comprehensive system overview overview: @just utils::overview # Show information about specified topic (try: info, status, config, overview, aliases, modules, help) show *TOPIC: #!/usr/bin/env bash TOPIC="{{TOPIC}}" if [ -z "$TOPIC" ]; then echo "📋 Available topics to show:" echo " info - Project information" echo " status - Application health status" echo " config - Configuration settings" echo " overview - System overview" echo " aliases - List of command aliases" echo " modules - Available modules" echo " build-tools - Build tools system" echo " help - Help system" echo "" echo "Usage: just show or just sh " exit 0 fi case "$TOPIC" in "info"|"information") just utils::info ;; "status"|"health") just utils::health ;; "config"|"configuration") just utils::config ;; "overview"|"system") just utils::overview ;; "aliases"|"alias") just list-alias ;; "modules"|"module") just helptext::modules ;; "build-tools"|"tools"|"tool") just helptext::tools ;; "help") just help ;; *) echo "📋 Available topics to show:" echo " info - Project information" echo " status - Application health status" echo " config - Configuration settings" echo " overview - System overview" echo " aliases - List of command aliases" echo " modules - Available modules" echo " build-tools - Build tools system" echo " help - Help system" echo "" echo "Usage: just show or just sh " ;; esac # ============================================================================= # PRIMARY WORKFLOW COMMANDS (Unified Interface) # ============================================================================= # Start development server (main entry point) start: @just dev::serve # Backward compatibility: redirect 'dev' to 'start' dev-start: @echo "💡 Note: 'just dev' has been renamed to 'just start'" @echo "🔄 Redirecting to development server..." @just start # Start development server with full features dev-full: @just dev::full # Build for development build-dev: @just build::dev # Build for production build-prod: @just build::prod # Smoke-test the htmx-ssr surface after a build (full page / fragment / theme / lang) htmx-smoke base="http://127.0.0.1:3030": @set -e; BASE="{{base}}"; \ echo "→ full page must include and /assets/htmx/htmx.min.js"; \ curl -fsS "$BASE/" | grep -q " and "; \ resp=$(curl -fsS -H "HX-Request: true" "$BASE/"); \ echo "$resp" | grep -qv "[^"]+)"' | get p?.0? | default "unknown" ) let chosen = if ("{{ profile }}" == "") { print "" print $" Current rendering profile: (ansi yellow_bold)($current)(ansi reset)" print "" for i in ($profiles | enumerate) { let marker = if $i.item.name == $current { $"(ansi green)▶(ansi reset)" } else { " " } print $" ($marker) [($i.index + 1)] ($i.item.label)" } print "" let raw = (input " Select [1/2] or Enter to cancel: " | str trim) if ($raw == "") { print " Cancelled."; exit 0 } let idx = ($raw | into int | $in - 1) if $idx < 0 or $idx >= ($profiles | length) { error make { msg: $"Invalid selection: ($raw)" } } $profiles | get $idx | get name } else { "{{ profile }}" } let valid_names = ($profiles | get name) if ($chosen not-in $valid_names) { error make { msg: $"Unknown profile '($chosen)'. Valid: ($valid_names | str join ', ')" } } if $chosen == $current { print $" Already on ($chosen) — nothing to do." exit 0 } open $ncl | str replace --regex 'default_profile = "(leptos-hydration|htmx-ssr)"' $'default_profile = "($chosen)"' | save -f $ncl print $" ✅ ($current) → ($chosen)" print "" if $chosen == "htmx-ssr" { print $" Dev: (ansi cyan)just dev::htmx(ansi reset) — cargo watch, no wasm32" print $" Prod: (ansi cyan)just build-auto(ansi reset) — server-only binary" } else { print $" Dev: (ansi cyan)just start(ansi reset) — cargo leptos serve" print $" Prod: (ansi cyan)just build-auto(ansi reset) — cargo leptos build --release" } # Build for production with automatic WASM-or-native dispatch driven by site/config/rendering.ncl (ADR-006) build-auto: @nu /Users/Akasha/Development/rustelo/scripts/check-wasm-needed.nu --verbose \ --routes-dir site/config \ --workspace-config site/config/rendering.ncl \ && (echo "🔨 WASM required — cargo leptos build --release"; cargo leptos build --release) \ || (echo "🪶 Pure htmx-ssr — skipping wasm32"; \ cargo build --release -p rustelo-leptos-server --no-default-features --features htmx-ssr) # Serve production build serve-prod: @just build::serve-prod # Serve with CMS features serve-cms: @just build::serve-cms # Run all tests test-run: @just test::run # Quality checks with mandatory rule validation (main interface) quality: @echo "🔥 Running quality checks with MANDATORY rule validation..." @echo "📖 Reading critical rules from @rules/CLAUDE_CRITICAL_RULES.md..." @scripts/rules/validate-rules.nu --strict @just test::quality # Build CSS files css-build: @just dev::css-build # Watch CSS files css-watch: @just dev::css-watch # Database setup db-setup: @just database::setup # Database migrations db-migrate: @just database::migrate # Generate documentation docs-generate: @just docs::generate # Build documentation docs-build: @just docs::build # Check code quality check: @just test::check # Format code fmt: @just test::format # Fast development modes dev-fast: @just dev::dev-fast dev-coordinated: @just dev::dev-coordinated dev-minimal: @just dev::ultra-minimal build-artifacts: @just dev::build-artifacts build-status: @just dev::build-status clean-build-artifacts: @just dev::clean-build-artifacts # Complete project setup setup: @just utils::setup # Project information info: @just utils::info # Health check health: @just utils::health # ============================================================================= # NAVIGATION TESTING SHORTCUTS (Common Routes) # ============================================================================= # Test home route nav-test-home: @just dev::nav-test-route / # Test services route nav-test-services: @just dev::nav-test-route /services # Test contact route nav-test-contact: @just dev::nav-test-route /contact # Test blog route nav-test-blog: @just dev::nav-test-route /blog # Test Spanish home nav-test-es: @just dev::nav-test-route /es # Test Spanish contact nav-test-contactar: @just dev::nav-test-route /es/contactar # Clean build artifacts clean: @just build::clean # ============================================================================= # CONVENIENCE COMMANDS (Direct Module Access) # ============================================================================= # Browser testing page-tester *ARGS: @just test::page {{ARGS}} pages-report *ARGS: @just test::pages-report {{ARGS}} page-new: @just test::page-new # Cross-platform build cross-build: @just build::cross # Content operations content-build: @just dev::content-build # Export NCL metadata to index.json (NCL pipeline) content-ncl-to-json type="" lang="": @just dev::content-ncl-to-json {{type}} {{lang}} # Full NCL pipeline: _index.ncl → index.json + copy images content-ncl-build type="" lang="": @just dev::content-ncl-build {{type}} {{lang}} # Copy page-bundle images to site/public for HTTP serving content-copy-images type="" lang="": @just dev::content-copy-images {{type}} {{lang}} # Sync FTL files from source project index.html files (requires data-key attributes). # Each project index.ncl must have source_html set. sync-pages: nu scripts/sync/sync-all-pages.nu # Sync a single project FTL. Usage: just sync-page ontoref sync-page project: nu scripts/sync/sync-all-pages.nu --only {{project}} # Preview FTL sync without writing. Usage: just sync-page-dry ontoref sync-page-dry project: nu scripts/sync/sync-all-pages.nu --only {{project}} --dry-run # Sync site/public → target/site (mirrors what cargo-leptos does at build time). # Use when the dev server is not running and static assets need to be available immediately. sync-public: @rsync -a --exclude='.DS_Store' site/public/ target/site/ @echo "synced site/public → target/site" content-generate type title *args: @just dev::content-generate {{type}} {{title}} {{args}} content-generate-indices: @just dev::content-generate-indices # Generate *.ncl metadata files from existing markdown frontmatter content-md-to-ncl type="" lang="": @nu scripts/content/md-to-ncl.nu \ --content-dir "${SITE_CONTENT_PATH:-site/content}" \ {{ if type != "" { "--type " + type } else { "" } }} \ {{ if lang != "" { "--lang " + lang } else { "" } }} # Fill translations field in all *.ncl files by cross-lang stem matching (implies --force) content-md-to-ncl-translations type="" lang="": @nu scripts/content/md-to-ncl.nu --fill-translations \ --content-dir "${SITE_CONTENT_PATH:-site/content}" \ {{ if type != "" { "--type " + type } else { "" } }} \ {{ if lang != "" { "--lang " + lang } else { "" } }} # Validate all generated post *.ncl files pass their Nickel contracts content-ncl-validate type="" lang="": @nu scripts/content/md-to-ncl.nu --validate-contracts \ --content-dir "${SITE_CONTENT_PATH:-site/content}" \ {{ if type != "" { "--type " + type } else { "" } }} \ {{ if lang != "" { "--lang " + lang } else { "" } }} # Generate _index.ncl files from per-post *.ncl metadata files # Generate _index.ncl files. Pass validate=true to also check slug/id uniqueness. # Usage: just content-ncl-index [type] [lang] [validate] content-ncl-index type="" lang="" validate="": @nu scripts/content/generate-ncl-index.nu \ --content-dir "${SITE_CONTENT_PATH:-site/content}" \ {{ if type != "" { "--type " + type } else { "" } }} \ {{ if lang != "" { "--lang " + lang } else { "" } }} \ {{ if validate != "" { "--validate" } else { "" } }} # Generate + validate slug/id uniqueness in one step content-ncl-index-validate type="" lang="": @nu scripts/content/generate-ncl-index.nu --validate \ --content-dir "${SITE_CONTENT_PATH:-site/content}" \ {{ if type != "" { "--type " + type } else { "" } }} \ {{ if lang != "" { "--lang " + lang } else { "" } }} # Same as content-ncl-index but shows what would be written without writing content-ncl-index-dry type="" lang="": @nu scripts/content/generate-ncl-index.nu --dry-run --verbose \ --content-dir "${SITE_CONTENT_PATH:-site/content}" \ {{ if type != "" { "--type " + type } else { "" } }} \ {{ if lang != "" { "--lang " + lang } else { "" } }} # Standalone build-tools generation command build-tools-info: @just dev::build-tools-info # Tools operations build-tools-analyze format="markdown" output="site/info": @just tools::build-tools-analyze {{format}} {{output}} build-tools-manage mode="dashboard": @just tools::tools-manage {{mode}} build-tools-generate-page name template="basic": @just tools::build-tools-generate-page {{name}} {{template}} build-tools-status: @just tools::build-tools-status # Install development dependencies npm-install: @just utils::npm-install cargo-check: @just utils::cargo-check # ============================================================================= # WORKFLOW COMMANDS # ============================================================================= # Complete development workflow workflow-dev: @echo "🔄 Running development workflow..." @just utils::setup-deps @just css-build @just check @just test @just dev # Complete production workflow workflow-prod: @echo "🔄 Running production workflow..." @just test::quality @just build-prod @just build::docker @just deploy # Pre-commit workflow pre-commit: @echo "🔄 Running pre-commit workflow..." @just fmt @just test::check-strict @just test @just css-build # CI/CD workflow ci: @echo "🔄 Running CI/CD workflow..." @just test::format-check @just test::check-strict @just test @just test::audit @just build-prod # ============================================================================= # HELP COMMANDS (Delegated to help module) # ============================================================================= # Show help for development commands help-dev: @just helptext::dev # Show help for build commands help-build: @just helptext::build # Show help for testing commands help-test: @just helptext::test # Show help for database commands help-db: @just helptext::db # Show help for documentation commands help-docs: @just helptext::docs # Show help for utility commands help-utils: @just helptext::utils # Show help for build-tools commands help-build-tools: @just helptext::build-tools # Show help for modules help-modules: @just helptext::modules # Show comprehensive help help-all: @just helptext::all # Main help entry point help: @just helptext::main # Help with topic argument help-topic TOPIC: @just helptext::topic {{TOPIC}} # Alias h that redirects to help with arguments h *TOPIC: #!/usr/bin/env bash TOPIC="{{TOPIC}}" if [ -n "$TOPIC" ]; then just help-topic "$TOPIC" else just help fi # Logo (delegated to help module) logo: @just helptext::logo server-browser-logs: @just dev::server-browser-logs browser-tools-server: @just dev::browser-tools-server browser-logs page="/": @just dev::browser-logs {{page}} # ============================================================================= # LOCAL INSTALL # Builds the leptos-hydration binary + WASM bundle, installs the binary to # ~/.local/libexec, syncs rustelo nickel resources, copies the compiled site # tree, and writes the site-root-aware wrapper to ~/.local/bin/rustelo-leptos-server. # ============================================================================= local-install: #!/usr/bin/env nu let nickel_path = $"{{ rustelo_root }}/resources/nickel:{{ justfile_directory() }}/site/config" let site_cfg = "{{ justfile_directory() }}/site/config/index.ncl" print "→ building rustelo-leptos-server (release, leptos-hydration)" with-env { NICKEL_IMPORT_PATH: $nickel_path, SITE_CONFIG_PATH: $site_cfg } { ^cargo leptos build --release --features content-static } let cargo_cfg = "{{ justfile_directory() }}/.cargo/config.toml" let target_dir = ( $env.CARGO_TARGET_DIR? | default ( if ($cargo_cfg | path exists) { (open $cargo_cfg).build?."target-dir"? | default "{{ justfile_directory() }}/target" } else { "{{ justfile_directory() }}/target" } ) ) let home = $env.HOME let libexec = ($home | path join ".local/libexec") let bin_dir = ($home | path join ".local/bin") let share_dir = ($home | path join ".local/share/rustelo-leptos-server") let nickel_dir = ($home | path join ".local/share/rustelo/nickel") mkdir $libexec $bin_dir $share_dir $nickel_dir print "→ installing binary → ~/.local/libexec/rustelo-leptos-server" cp ($target_dir | path join "release/rustelo-leptos-server") ($libexec | path join "rustelo-leptos-server") print "→ syncing rustelo nickel → ~/.local/share/rustelo/nickel" ^rsync -a --delete $"{{ rustelo_root }}/resources/nickel/" $"($nickel_dir)/" print "→ installing compiled site tree (pkg/ + assets) → ~/.local/share/rustelo-leptos-server/site" ^rsync -a --delete ($target_dir | path join "site/") ($share_dir | path join "site/") print "→ writing wrapper → ~/.local/bin/rustelo-leptos-server" let wrapper_dst = ($bin_dir | path join "rustelo-leptos-server") cp "{{ justfile_directory() }}/scripts/local-install/rustelo-leptos-server.sh" $wrapper_dst ^chmod 755 $wrapper_dst print "" print "✅ done — usage:" print " rustelo-leptos-server # auto-detects site/ in $PWD" print " rustelo-leptos-server --site # explicit workspace root" print $" # or place config at ($home)/.config/rustelo-leptos-server/site/"