#!/usr/bin/env nu # Workspace Initialization Tool # Creates new workspace with proper directory structure for KCL package and module loader systems use ../core/nulib/lib_provisioning/config/accessor.nu * # Get dependency configuration (interactive or from flags) def get-dependency-config [ workspace_path: string dep_option?: string dep_url?: string ]: nothing -> record { # If dep_option provided, use it; otherwise prompt let option = if ($dep_option | is-not-empty) { $dep_option } else { print "\nšŸ“¦ Provisioning Dependency Configuration" print " Choose how to configure the provisioning package dependency:\n" print " 1. workspace-home (default) - Install in workspace .kcl directory (self-contained)" print " 2. home-package - Use ~/.kcl/packages/provisioning (shared across workspaces)" print " 3. git-package - Use Git repository" print " 4. publish-repo - Use KCL registry\n" let choice = (input " Select option [1-4] (default: 1): ") let normalized_choice = if ($choice | is-empty) { "1" } else { $choice } match $normalized_choice { "1" => "workspace-home", "2" => "home-package", "3" => "git-package", "4" => "publish-repo", "workspace-home" => "workspace-home", "home-package" => "home-package", "git-package" => "git-package", "publish-repo" => "publish-repo", _ => { print $" āš ļø Invalid choice '($normalized_choice)', using default: workspace-home" "workspace-home" } } } # Handle each option match $option { "workspace-home" => { print " āœ“ Using workspace-local provisioning package" # Always run install - it will check version and update if needed install-workspace-provisioning $workspace_path { type: "workspace-home" path: ".kcl/packages/provisioning" version: "0.0.1" } }, "home-package" => { print " āœ“ Using home directory provisioning package" # Always run install - it will check version and update if needed install-home-provisioning { type: "home-package" path: "~/.kcl/packages/provisioning" version: "0.0.1" } }, "git-package" => { let git_url = if ($dep_url | is-not-empty) { $dep_url } else { input " Enter Git repository URL: " } print $" āœ“ Using Git repository: ($git_url)" { type: "git-package" git: $git_url version: "0.0.1" } }, "publish-repo" => { let repo_url = if ($dep_url | is-not-empty) { $dep_url } else { input " Enter KCL registry URL (or leave empty for default): " } if ($repo_url | is-not-empty) { print $" āœ“ Using registry: ($repo_url)" { type: "publish-repo" registry: $repo_url version: "0.0.1" } } else { print " āœ“ Using default KCL registry" { type: "publish-repo" version: "0.0.1" } } }, _ => { print $" āš ļø Unknown option '($option)', using workspace-home" { type: "workspace-home" path: ".kcl/packages/provisioning" version: "0.0.1" } } } } # Install provisioning package to workspace .kcl directory def install-workspace-provisioning [workspace_path: string]: nothing -> nothing { let workspace_abs = ($workspace_path | path expand) let workspace_kcl_dir = ($workspace_abs | path join ".kcl" "packages") let workspace_prov_dir = ($workspace_kcl_dir | path join "provisioning") # Create .kcl/packages directory mkdir $workspace_kcl_dir # Determine source path for provisioning/kcl # Try to find provisioning root let script_dir = ($env.FILE_PWD? | default (pwd)) let provisioning_root = ($script_dir | path dirname | path dirname) let kcl_source = ($provisioning_root | path join "kcl") # Check if source exists if not ($kcl_source | path exists) { # Try alternative: check if PROVISIONING env var is set let alt_source = try { let config = (get-config) let base_path = ($config.paths.base? | default "") if ($base_path | is-not-empty) { $base_path | path join "kcl" } else { "" } } catch { "" } if ($alt_source | is-not-empty) and ($alt_source | path exists) { # Check version and update if needed if (check-and-update-package $workspace_prov_dir $alt_source) { print $" šŸ“‹ Copying provisioning KCL package from: ($alt_source)" cp -r $alt_source $workspace_prov_dir } } else { error make { msg: $"Cannot find provisioning KCL package. Tried: ($kcl_source), ($alt_source)" } } } else { # Check version and update if needed if (check-and-update-package $workspace_prov_dir $kcl_source) { print $" šŸ“‹ Copying provisioning KCL package from: ($kcl_source)" cp -r $kcl_source $workspace_prov_dir } # Also create distribution package for sharing/reuse build-distribution-package $provisioning_root $kcl_source } print $" āœ… Provisioning package ready at: ($workspace_prov_dir)" } # Install provisioning package to home .kcl directory def install-home-provisioning []: nothing -> nothing { let home_kcl_dir = ($env.HOME | path join ".kcl" "packages") let home_prov_dir = ($home_kcl_dir | path join "provisioning") # Create .kcl/packages directory mkdir $home_kcl_dir # Determine source path for provisioning/kcl # Try to find provisioning root let script_dir = ($env.FILE_PWD? | default (pwd)) let provisioning_root = ($script_dir | path dirname | path dirname) let kcl_source = ($provisioning_root | path join "kcl") # Check if source exists if not ($kcl_source | path exists) { # Try alternative: check if PROVISIONING env var is set let alt_source = try { let config = (get-config) let base_path = ($config.paths.base? | default "") if ($base_path | is-not-empty) { $base_path | path join "kcl" } else { "" } } catch { "" } if ($alt_source | is-not-empty) and ($alt_source | path exists) { # Check version and update if needed if (check-and-update-package $home_prov_dir $alt_source) { print $" šŸ“‹ Copying provisioning KCL package from: ($alt_source)" cp -r $alt_source $home_prov_dir } } else { error make { msg: $"Cannot find provisioning KCL package. Tried: ($kcl_source), ($alt_source)" } } } else { # Check version and update if needed if (check-and-update-package $home_prov_dir $kcl_source) { print $" šŸ“‹ Copying provisioning KCL package from: ($kcl_source)" cp -r $kcl_source $home_prov_dir } # Also create distribution package for sharing/reuse build-distribution-package $provisioning_root $kcl_source } print $" āœ… Provisioning package ready at: ($home_prov_dir)" } # Check package version and determine if update is needed # Returns true if package should be copied/updated, false if already up to date def check-and-update-package [ target_dir: string source_dir: string ]: nothing -> bool { # If target doesn't exist, needs installation if not ($target_dir | path exists) { print $" šŸ“¦ Installing new provisioning package..." return true } # Get source version let source_version = get-kcl-version $source_dir # Get installed version let installed_version = get-kcl-version $target_dir # Compare versions if $source_version != $installed_version { print $" šŸ”„ Updating provisioning package: ($installed_version) → ($source_version)" print $" šŸ—‘ļø Removing old version..." rm -rf $target_dir return true } else { print $" āœ“ Provisioning package already up to date (v($installed_version))" return false } } # Get KCL package version from kcl.mod file def get-kcl-version [kcl_path: string]: nothing -> string { let kcl_mod = ($kcl_path | path join "kcl.mod") if not ($kcl_mod | path exists) { return "unknown" } try { let mod_content = (open $kcl_mod | from toml) $mod_content.package?.version? | default "unknown" } catch { "unknown" } } # Build distribution package from KCL source def build-distribution-package [provisioning_root: string, kcl_source: string]: nothing -> nothing { let dist_dir = ($provisioning_root | path join "distribution" "packages") let registry_dir = ($provisioning_root | path join "distribution" "registry") # Create distribution directories mkdir $dist_dir mkdir $registry_dir # Generate package info let version = try { let kcl_mod = ($kcl_source | path join "kcl.mod") if ($kcl_mod | path exists) { let mod_content = (open $kcl_mod | from toml) $mod_content.package?.version? | default "0.0.1" } else { "0.0.1" } } catch { "0.0.1" } let package_name = $"provisioning-kcl-($version).tar.gz" let package_path = ($dist_dir | path join $package_name) # Check if package already exists and is up to date if ($package_path | path exists) { let pkg_time = (ls $package_path | get 0.modified) let src_time = (ls $kcl_source | sort-by modified -r | get 0.modified) if $pkg_time > $src_time { print $" ā„¹ļø Distribution package is up to date: ($package_name)" return } } print $" šŸ“¦ Building distribution package: ($package_name)" # Create temporary staging directory let staging_dir = ($dist_dir | path join ".staging") mkdir $staging_dir let staging_prov = ($staging_dir | path join "provisioning") # Copy KCL files to staging cp -r $kcl_source $staging_prov # Create README for distribution let readme_content = $"# Provisioning KCL Package Version: ($version) Generated: (date now | format date '%Y-%m-%d %H:%M:%S') ## Installation ### Option 1: Workspace-local installation Copy this package to your workspace: ```bash cp -r provisioning /path/to/workspace/.kcl/packages/ ``` ### Option 2: User-level installation Install to your home directory: ```bash mkdir -p ~/.kcl/packages cp -r provisioning ~/.kcl/packages/ ``` ### Option 3: Using workspace init When initializing a workspace, choose 'workspace-home' option: ```bash provisioning ws init myworkspace # Select option 1 \(workspace-home\) ``` ## Usage In your KCL files: ```kcl import provisioning.settings as settings import provisioning.server as server import provisioning.defaults as defaults ``` ## Contents This package contains the core provisioning KCL schemas including: - settings.k - Main settings schema - server.k - Server configuration schema - defaults.k - Default values and constants - And other core schemas For more information, visit the provisioning documentation. " $readme_content | save ($staging_dir | path join "README.md") # Create package archive try { cd $staging_dir tar czf $package_path provisioning README.md cd $dist_dir # Go back before cleanup print $" āœ… Created distribution package: ($package_path)" # Update registry update-package-registry $registry_dir $package_name $version $kcl_source # Clean up staging rm -rf $staging_dir } catch { print $" āš ļø Warning: Could not create distribution package: ($in)" # Try cleanup anyway try { rm -rf $staging_dir } catch { } } } # Update package registry with metadata def update-package-registry [ registry_dir: string package_name: string version: string source_path: string ]: nothing -> nothing { let registry_file = ($registry_dir | path join "packages.json") # Load existing registry or create new let registry = if ($registry_file | path exists) { open $registry_file | from json } else { { packages: [] } } # Create package entry let package_entry = { name: "provisioning" version: $version package_file: $package_name created_at: (date now | format date '%Y-%m-%d %H:%M:%S') source_path: $source_path type: "kcl-package" description: "Core provisioning KCL schemas and modules" } # Update or add package entry let updated_packages = ( $registry.packages | where name != "provisioning" or version != $version | append $package_entry ) let updated_registry = { packages: $updated_packages } # Save registry $updated_registry | to json | save -f $registry_file print $" šŸ“‹ Updated package registry: ($registry_file)" } # Load default modules to infrastructure layer def load-default-modules [workspace_path: string, infra_path: string]: nothing -> nothing { let workspace_abs = ($workspace_path | path expand) let infra_abs = ($infra_path | path expand) # Determine provisioning root and module loader script let script_dir = ($env.FILE_PWD? | default (pwd)) let provisioning_root = ($script_dir | path dirname) let module_loader = ($provisioning_root | path join "core" "cli" "module-loader") # Verify module loader exists if not ($module_loader | path exists) { print $" āš ļø Warning: Module loader not found at ($module_loader)" print $" šŸ’” You can load modules manually: cd infra/ && provisioning mod load taskservs . os" return } # Load os taskserv to infrastructure layer try { print $" šŸ“¦ Loading os taskserv to infrastructure layer..." ^nu $module_loader "load" "taskservs" $infra_abs "os" print $" āœ… Loaded os taskserv" } catch { print $" āš ļø Warning: Could not load os taskserv: ($in)" print $" šŸ’” You can load it manually: cd ($infra_path) && provisioning mod load taskservs . os" } } # Main workspace initialization command def main [ workspace_path: string --infra-name: string # Infrastructure name --template: string # Template type: minimal, full, example --workspace-type: string # Workspace type: development, staging, production --user-name: string # User name for workspace --taskservs: list # Taskservs to load during init --providers: list # Providers to load during init --clusters: list # Clusters to load during init --dep-option: string # Dependency option: home-package, git-package, publish-repo, workspace-home --dep-url: string # Dependency URL for git-package or publish-repo --overwrite # Overwrite existing workspace --check # Check mode only (dry-run) ] { # Validate workspace name - no hyphens allowed (causes KCL module resolution issues) let workspace_name = ($workspace_path | path basename) if ($workspace_name | str contains "-") { print $"āŒ Error: Workspace name cannot contain hyphens: '($workspace_name)'" print "" print " Hyphens in workspace names cause KCL module resolution issues." print $" Use underscores instead: '($workspace_name | str replace -a '-' '_')'" print "" exit 1 } # Validate infra name if provided - no hyphens allowed if ($infra_name | is-not-empty) and ($infra_name | str contains "-") { print $"āŒ Error: Infrastructure name cannot contain hyphens: '($infra_name)'" print "" print " Hyphens in infrastructure names cause KCL module resolution issues." print $" Use underscores instead: '($infra_name | str replace -a '-' '_')'" print "" exit 1 } if $check { let infra_dir_name = if ($infra_name | is-not-empty) { $infra_name } else { "main" } let template_to_use = if ($template | is-not-empty) { $template } else { "minimal" } print $"šŸ” [CHECK MODE] Would initialize workspace: ($workspace_path)" print $" Template: ($template_to_use)" print $" Type: ($workspace_type | default 'development')" print $" Infrastructure directory: infra/($infra_dir_name)" print "" print " Structure to create:" print $" ($workspace_path)/" print " ā”œā”€ā”€ infra/" print $" │ └── ($infra_dir_name)/" print " │ ā”œā”€ā”€ .taskservs/" print " │ ā”œā”€ā”€ .providers/" print " │ ā”œā”€ā”€ .clusters/" print " │ ā”œā”€ā”€ .manifest/" print " │ ā”œā”€ā”€ kcl.mod" print " │ └── servers.k" print " ā”œā”€ā”€ data/" print " ā”œā”€ā”€ tmp/" print " └── resources/" if not ($taskservs | is-empty) { print "" print $" Taskservs to load: ($taskservs | str join ', ')" } if not ($providers | is-empty) { print $" Providers to load: ($providers | str join ', ')" } if not ($clusters | is-empty) { print $" Clusters to load: ($clusters | str join ', ')" } return } let workspace_abs = ($workspace_path | path expand) # Check if workspace already exists if ($workspace_abs | path exists) and not $overwrite { print $"āŒ Workspace already exists: ($workspace_path)" print " Use --overwrite to overwrite existing workspace" exit 1 } print $"šŸš€ Initializing workspace: ($workspace_path)" let infra_dir_name = if ($infra_name | is-not-empty) { $infra_name } else { "main" } let template_to_use = if ($template | is-not-empty) { $template } else { "minimal" } # Determine provisioning dependency configuration let dep_config = get-dependency-config $workspace_abs $dep_option $dep_url # Create workspace directory structure let workspace_info = create-workspace-structure $workspace_path $infra_dir_name # Create basic configuration files create-workspace-config $workspace_path $workspace_info.infra_path $infra_dir_name $dep_config # Create example files from template create-workspace-examples $workspace_path $workspace_info.infra_path $infra_dir_name $template_to_use # Load default os taskserv module to infrastructure print "" print "šŸ“¦ Loading default modules..." load-default-modules $workspace_path $workspace_info.infra_path print "" print $"āœ… Workspace initialized successfully: ($workspace_path)" print $"šŸ“ Workspace structure created" print $"šŸ“‚ Infrastructure created: infra/($infra_dir_name)" print $"šŸ“‹ Template applied: ($template_to_use)" print $"šŸ“„ Configuration files created" print $"šŸ“¦ Default modules loaded: os taskserv" print "" print "Next steps:" print $" 1. cd ($workspace_path)/infra/($infra_dir_name)" print " 2. Edit servers.k to customize your infrastructure" print " 3. Load additional modules:" print " - provisioning dt # Discover available taskservs" print " - cd /infra/ && provisioning mod load taskservs . " print $" 4. Deploy: provisioning s create --infra ($infra_dir_name)" print "" print "Quick start:" print $" cd ($workspace_path)/infra/($infra_dir_name)" print " kcl run servers.k # Validate configuration" } # Create workspace directory structure def create-workspace-structure [ workspace_path: string infra_name: string ]: nothing -> record { let workspace_abs = ($workspace_path | path expand) let infra_dir_name = if ($infra_name | is-not-empty) { $infra_name } else { "main" } # Create workspace-level directories (non-infrastructure) mkdir $workspace_abs mkdir ($workspace_abs | path join "data") mkdir ($workspace_abs | path join "tmp") mkdir ($workspace_abs | path join "resources") # Create Layer 2 (workspace-level) module directories mkdir ($workspace_abs | path join ".taskservs") mkdir ($workspace_abs | path join ".providers") mkdir ($workspace_abs | path join ".clusters") mkdir ($workspace_abs | path join ".manifest") # Create infrastructure directory structure let infra_path = ($workspace_abs | path join "infra" | path join $infra_dir_name) mkdir $infra_path # Create Layer 3 (infrastructure-level) module directories mkdir ($infra_path | path join ".taskservs") mkdir ($infra_path | path join ".providers") mkdir ($infra_path | path join ".clusters") mkdir ($infra_path | path join ".manifest") # Create module-loader expected directories mkdir ($infra_path | path join "taskservs") mkdir ($infra_path | path join "overrides") mkdir ($infra_path | path join "defs") mkdir ($infra_path | path join "config") { path: $workspace_abs infra_path: $infra_path infra_name: $infra_dir_name created: (date now | format date "%Y-%m-%d %H:%M:%S") workspace_dirs: ["data", "tmp", "resources"] workspace_modules: [".taskservs", ".providers", ".clusters", ".manifest"] infra_dirs: [".taskservs", ".providers", ".clusters", ".manifest"] } } # Create basic workspace configuration files def create-workspace-config [ workspace_path: string infra_path: string infra_name: string dep_config: record ]: nothing -> nothing { let workspace_abs = ($workspace_path | path expand) # Generate dependency line based on configuration let dep_line = match $dep_config.type { "workspace-home" => { $"provisioning = \{ path = \"../../($dep_config.path)\", version = \"($dep_config.version)\" \}" }, "home-package" => { $"provisioning = \{ path = \"($dep_config.path)\", version = \"($dep_config.version)\" \}" }, "git-package" => { $"provisioning = \{ git = \"($dep_config.git)\", version = \"($dep_config.version)\" \}" }, "publish-repo" => { if ($dep_config.registry? | is-not-empty) { $"provisioning = \{ registry = \"($dep_config.registry)\", version = \"($dep_config.version)\" \}" } else { $"provisioning = \{ version = \"($dep_config.version)\" \}" } }, _ => { $"provisioning = \{ path = \"~/.kcl/packages/provisioning\", version = \"0.0.1\" \}" } } # Create kcl.mod in infra directory let kcl_mod_content = $"[package] name = \"($infra_name)\" edition = \"v0.11.3\" version = \"0.0.1\" [dependencies] # Provisioning package dependency \(configured during workspace init\) ($dep_line) " $kcl_mod_content | save ($infra_path | path join "kcl.mod") # Create .gitignore at workspace root let base_gitignore = "# Workspace runtime data data/ tmp/ *.log # Infrastructure module directories (managed by module-loader) infra/**/.taskservs/ infra/**/.providers/ infra/**/.clusters/ infra/**/.manifest/ # Generated files infra/**/taskservs.k infra/**/providers.k infra/**/clusters.k # Secrets and sensitive data *.age *.enc *.key " # Add .kcl to gitignore if using workspace-home let gitignore_content = if $dep_config.type == "workspace-home" { $"($base_gitignore) # Workspace-local KCL packages \(managed by workspace init\) .kcl/ " } else { $base_gitignore } $gitignore_content | save ($workspace_abs | path join ".gitignore") # Create empty manifest files in infra directory let empty_manifest = { loaded_taskservs: [] loaded_providers: [] loaded_clusters: [] last_updated: (date now | format date "%Y-%m-%d %H:%M:%S") infra_path: $infra_path } $empty_manifest | to yaml | save ($infra_path | path join ".manifest" | path join "taskservs.yaml") $empty_manifest | to yaml | save ($infra_path | path join ".manifest" | path join "providers.yaml") $empty_manifest | to yaml | save ($infra_path | path join ".manifest" | path join "clusters.yaml") } # Load template file def load-template [ template_name: string file_name: string ]: nothing -> string { # Try to find provisioning root let provisioning_root = $env.PROVISIONING? | default "/usr/local/provisioning" let template_path = ($provisioning_root | path join "templates" "workspace" $template_name $file_name) if ($template_path | path exists) { open $template_path } else { # Return empty string if template not found (will use fallback) "" } } # Create example workspace files def create-workspace-examples [ workspace_path: string infra_path: string infra_name: string template_name: string = "minimal" ]: nothing -> nothing { let workspace_abs = ($workspace_path | path expand) # Load servers.k template let servers_template = load-template $template_name "servers.k" let servers_example = if ($servers_template | is-not-empty) { $servers_template } else { # Fallback to minimal template if template not found load-template "minimal" "servers.k" } $servers_example | save ($infra_path | path join "servers.k") # Load template README if available let template_readme = load-template $template_name "README.md" # Create workspace README using simple string concatenation let ws_name = ($workspace_path | path basename) # Use simple string interpolation for README content let readme_content = $"# Workspace: ($ws_name) This workspace was initialized with the provisioning workspace system. ## Structure ``` ($ws_name)/ ā”œā”€ā”€ .taskservs/ # Layer 2: Workspace-shared taskserv modules ā”œā”€ā”€ .providers/ # Layer 2: Workspace-shared provider modules ā”œā”€ā”€ .clusters/ # Layer 2: Workspace-shared cluster modules ā”œā”€ā”€ .manifest/ # Layer 2: Workspace-level manifests ā”œā”€ā”€ infra/ # Infrastructure definitions │ └── ($infra_name)/ # Infrastructure: ($infra_name) │ ā”œā”€ā”€ .taskservs/ # Layer 3: Infrastructure-specific overrides │ ā”œā”€ā”€ .providers/ # Layer 3: Infrastructure-specific overrides │ ā”œā”€ā”€ .clusters/ # Layer 3: Infrastructure-specific overrides │ ā”œā”€ā”€ .manifest/ # Layer 3: Infrastructure-level manifests │ ā”œā”€ā”€ kcl.mod # KCL module configuration │ └── servers.k # Server configuration ā”œā”€ā”€ data/ # Workspace-level runtime data ā”œā”€ā”€ tmp/ # Temporary files and deployment artifacts └── resources/ # Workspace-level resources and templates ``` ### 3-Layer Module Architecture The workspace uses a 3-layer module resolution system: 1. **Layer 1 - System**: Global extensions in provisioning/extensions/ 2. **Layer 2 - Workspace**: Shared modules in workspace .taskservs/, .providers/, .clusters/ 3. **Layer 3 - Infrastructure**: Infrastructure-specific overrides in infra//.taskservs/, .providers/, .clusters/ **Resolution order**: Layer 3 → Layer 2 → Layer 1 - higher layers override lower ### Infrastructure Directory Each infrastructure in infra// can: - Inherit shared modules from workspace layer -Layer 2- - Override with infrastructure-specific versions -Layer 3- - Define infrastructure-specific configuration -kcl.mod, servers.k- ## Usage ### 1. Navigate to Infrastructure Directory Use cd to navigate to your infrastructure directory. ### 2. Load Required Modules **Option A: Load at workspace level - shared across all infrastructures** Load shared modules at workspace level using provisioning mod load with --level workspace flag. **Option B: Load at infrastructure level - specific to one infrastructure** Load infrastructure-specific modules using provisioning mod load with --level infra flag. ### 3. Verify Module Loading Use provisioning mod list to verify loaded modules. ### 4. Configure Infrastructure Edit servers.k in the infrastructure directory to define your requirements. The loaded modules will be available for import. ### 5. Deploy Infrastructure Use kcl run to generate configuration and provisioning s create to deploy. ## Multiple Infrastructures You can have multiple infrastructure configurations in one workspace by running workspace init with different --infra names. ## Module Management - Use 'provisioning mod discover ' to find available modules - Use 'provisioning mod load ' to load modules - Use 'provisioning mod unload ' to remove modules - Module manifests track all loaded modules in each infra//.manifest/ The module directories -.taskservs/, .providers/, .clusters/- are managed automatically and should not be edited manually. " # Combine workspace README with template README let final_readme = if ($template_readme | is-not-empty) { $"($readme_content)\n\n---\n\n($template_readme)" } else { $readme_content } $final_readme | save ($workspace_abs | path join "README.md") # Also save template-specific README in infra directory if available if ($template_readme | is-not-empty) { $template_readme | save ($infra_path | path join "README.md") } } # Initialize workspace with specific modules export def "main init" [ workspace_path: string --infra-name: string # Infrastructure name --template: string # Template type: minimal, full, example --workspace-type: string # Workspace type: development, staging, production --user-name: string # User name for workspace --taskservs: list = [] # Taskservs to load during initialization --providers: list = [] # Providers to load during initialization --clusters: list = [] # Clusters to load during initialization --dep-option: string # Dependency option: home-package, git-package, publish-repo, workspace-home --dep-url: string # Dependency URL for git-package or publish-repo --overwrite # Overwrite existing workspace --check # Check mode only (dry-run) ]: nothing -> nothing { # Create basic workspace first main $workspace_path --infra-name $infra_name --template $template --workspace-type $workspace_type --user-name $user_name --taskservs $taskservs --providers $providers --clusters $clusters --dep-option $dep_option --dep-url $dep_url --overwrite=$overwrite --check=$check # Skip module loading in check mode if $check { return } # Load specified modules if not ($taskservs | is-empty) { print $"Loading taskservs: ($taskservs | str join ', ')" ../core/cli/module-loader load taskservs $workspace_path $taskservs } if not ($providers | is-empty) { print $"Loading providers: ($providers | str join ', ')" ../core/cli/module-loader load providers $workspace_path $providers } if not ($clusters | is-empty) { print $"Loading clusters: ($clusters | str join ', ')" ../core/cli/module-loader load clusters $workspace_path $clusters } print $"āœ… Workspace initialized with modules" } # Show workspace information export def "main info" [workspace_path: string]: nothing -> record { let workspace_abs = ($workspace_path | path expand) if not ($workspace_abs | path exists) { error make { msg: $"Workspace does not exist: ($workspace_abs)" } } let taskservs_manifest = try { open ($workspace_abs | path join ".manifest" | path join "taskservs.yaml") } catch { { loaded_taskservs: [] } } let providers_manifest = try { open ($workspace_abs | path join ".manifest" | path join "providers.yaml") } catch { { loaded_providers: [] } } let clusters_manifest = try { open ($workspace_abs | path join ".manifest" | path join "clusters.yaml") } catch { { loaded_clusters: [] } } { workspace: $workspace_abs taskservs_count: ($taskservs_manifest.loaded_taskservs | length) providers_count: ($providers_manifest.loaded_providers | length) clusters_count: ($clusters_manifest.loaded_clusters | length) taskservs: ($taskservs_manifest.loaded_taskservs | get name) providers: ($providers_manifest.loaded_providers | get name) clusters: ($clusters_manifest.loaded_clusters | get name) } } # Validate workspace structure export def "main validate" [workspace_path: string]: nothing -> record { let workspace_abs = ($workspace_path | path expand) let required_dirs = [".taskservs", ".providers", ".clusters", ".manifest"] let required_files = ["kcl.mod", "servers.k"] let missing_dirs = $required_dirs | where {|dir| not (($workspace_abs | path join $dir) | path exists) } let missing_files = $required_files | where {|file| not (($workspace_abs | path join $file) | path exists) } let is_valid = ($missing_dirs | is-empty) and ($missing_files | is-empty) { valid: $is_valid workspace: $workspace_abs missing_directories: $missing_dirs missing_files: $missing_files recommendations: (if not $is_valid { ["Run 'workspace-init.nu ' to fix workspace structure"] } else { [] }) } }