#!/usr/bin/env nu # Taskserv Discovery System (UPDATED for grouped structure) # Discovers available taskservs with metadata extraction from grouped directories use ../lib_provisioning/config/accessor.nu config-get # Discover all available taskservs (updated for grouped structure) export def discover-taskservs []: nothing -> list { # Get absolute path to extensions directory from config let taskservs_path = (config-get "paths.taskservs" | path expand) if not ($taskservs_path | path exists) { error make { msg: $"Taskservs path not found: ($taskservs_path)" } } # Find taskservs in both flat and grouped structure mut taskservs = [] # Get all items in taskservs directory let items = ls $taskservs_path | where type == "dir" for item in $items { let item_name = ($item.name | path basename) let kcl_path = ($item.name | path join "kcl") let kcl_mod_path = ($kcl_path | path join "kcl.mod") # Check if this is a direct taskserv (has kcl subdirectory) if ($kcl_mod_path | path exists) { let metadata = extract_taskserv_metadata $item_name $kcl_path "root" if ($metadata != null) { $taskservs = ($taskservs | append $metadata) } } else { # This might be a group directory, check for taskservs inside let group_items = try { ls $item.name } catch { [] } for group_item in ($group_items | where type == "dir") { let group_taskserv_name = ($group_item.name | path basename) let group_kcl_path = ($group_item.name | path join "kcl") let group_kcl_mod_path = ($group_kcl_path | path join "kcl.mod") if ($group_kcl_mod_path | path exists) { let metadata = extract_taskserv_metadata $group_taskserv_name $group_kcl_path $item_name if ($metadata != null) { $taskservs = ($taskservs | append $metadata) } } } } } $taskservs | sort-by name } # Extract metadata from a taskserv's KCL module (updated with group info) def extract_taskserv_metadata [name: string, kcl_path: string, group: string]: nothing -> record { let kcl_mod_path = ($kcl_path | path join "kcl.mod") # Try to parse TOML, skip if corrupted let mod_content = try { open $kcl_mod_path | from toml } catch { print $"⚠️ Skipping ($name): corrupted kcl.mod file" return null } # Find KCL schema files let schema_files = (glob ($kcl_path | path join "*.k")) let main_schema = ($schema_files | where ($it | str contains $name) | first | default "") # Extract dependencies let dependencies = ($mod_content.dependencies? | default {} | columns) # Get description from schema file if available let description = if ($main_schema != "") { extract_schema_description $main_schema } else { "" } { name: $name type: "taskserv" group: $group version: $mod_content.package.version kcl_path: $kcl_path main_schema: $main_schema dependencies: $dependencies description: $description available: true last_updated: (ls $kcl_mod_path | get 0.modified) } } # Extract description from KCL schema file def extract_schema_description [schema_file: string]: nothing -> string { if not ($schema_file | path exists) { return "" } # Read first few lines to find description let content = (open $schema_file | lines | take 10) let description_lines = ($content | where ($it | str starts-with "# ") | take 3) if ($description_lines | is-empty) { return "" } $description_lines | str replace "^# " "" | str join " " | str trim } # Search taskservs by name or description export def search-taskservs [query: string]: nothing -> list { discover-taskservs | where ($it.name | str contains $query) or ($it.description | str contains $query) } # Get specific taskserv info (updated to search both flat and grouped) export def get-taskserv-info [name: string]: nothing -> record { let taskservs = (discover-taskservs) let found = ($taskservs | where name == $name | first) if ($found | is-empty) { error make { msg: $"Taskserv '($name)' not found" } } $found } # List taskservs by group export def list-taskservs-by-group [group: string]: nothing -> list { discover-taskservs | where group == $group } # List all groups export def list-taskserv-groups []: nothing -> list { discover-taskservs | get group | uniq | sort } # List taskservs by category/tag (legacy support) export def list-taskservs-by-tag [tag: string]: nothing -> list { discover-taskservs | where ($it.description | str contains $tag) or ($it.group | str contains $tag) } # Validate taskserv availability export def validate-taskservs [names: list]: nothing -> record { let available = (discover-taskservs | get name) let missing = ($names | where ($it not-in $available)) let found = ($names | where ($it in $available)) { requested: $names found: $found missing: $missing valid: ($missing | is-empty) } } # Get taskserv path (helper for tools) export def get-taskserv-path [name: string]: nothing -> string { let taskserv_info = get-taskserv-info $name let base_path = "/Users/Akasha/project-provisioning/provisioning/extensions/taskservs" if $taskserv_info.group == "root" { $"($base_path)/($name)" } else { $"($base_path)/($taskserv_info.group)/($name)" } }