#!/usr/bin/env nu # Check environment prerequisites for ontoref operations. # # Usage: # nu reflection/bin/check-prereqs.nu # nu reflection/bin/check-prereqs.nu --context ci # nu reflection/bin/check-prereqs.nu --context agent # nu reflection/bin/check-prereqs.nu --form new_adr # nu reflection/bin/check-prereqs.nu --context local_dev --severity Hard def main [ --context: string = "local_dev", --form: string = "", --severity: string = "", --json, ] { let base_file = "reflection/requirements/base.ncl" let contexts_file = "reflection/requirements/contexts.ncl" # Inline daemon-export with subprocess fallback (standalone script, no module imports). let export_base = do { ^nickel export $base_file } | complete if $export_base.exit_code != 0 { error make { msg: "Failed to load base.ncl — is nickel installed?" } } let all_tools = ($export_base.stdout | from json | get tools) let export_ctx = do { ^nickel export $contexts_file } | complete if $export_ctx.exit_code != 0 { error make { msg: "Failed to load contexts.ncl" } } let ctx_candidates = ($export_ctx.stdout | from json | get contexts | where id == $context) if ($ctx_candidates | is-empty) { error make { msg: $"Unknown context '($context)'. Valid: local_dev | ci | agent | benchmark" } } let ctx_def = ($ctx_candidates | first) let tools = if ($form | is-empty) { $all_tools | where { |it| $it.contexts | any { |c| $c == $context } } } else { $all_tools | where { |it| $it.used_by_forms | any { |f| $f == $form } } } let tools = if ($severity | is-empty) { $tools } else { $tools | where { |it| $it.severity == $severity } } let results = $tools | each { |tool| let is_plugin = ($tool.plugin_name? | is-not-empty) # Presence check: plugin registry or PATH binary let present = if $is_plugin { plugin list | where name == $tool.plugin_name | is-not-empty } else { (do { run-external "which" $tool.binary } | complete | get exit_code) == 0 } # Version: run check_cmd via nu -c for both binary and plugin tools let version = if $present and ($tool.check_cmd | is-not-empty) { do { nu -c $"($tool.check_cmd) | str trim" } | complete | if $in.exit_code == 0 { $in.stdout | str trim } else { "unknown" } } else if $present { "present" } else { "not installed" } let version_ok = if $present and $version != "unknown" and $version != "present" { let min_parts = ($tool.version_min | split row "." | each { |p| $p | into int }) let act_result = ( $version | parse --regex $tool.version_extract | if ($in | is-empty) { null } else { $in | first | get capture0 } ) if ($act_result | is-empty) { true # Cannot parse version — assume ok (plugin compat versions) } else { let act_parts = ($act_result | split row "." | each { |p| $p | into int }) let major_ok = ($act_parts | get 0) >= ($min_parts | get 0) let minor_ok = if ($act_parts | get 0) == ($min_parts | get 0) { ($act_parts | get 1) >= ($min_parts | get 1) } else { true } $major_ok and $minor_ok } } else if $present { true } else { false } let config_ok = if $present and ($tool.config_check? | is-not-empty) { do { nu -c $tool.config_check } | complete | get exit_code | $in == 0 } else { true } let display_name = if $is_plugin { $"plugin:($tool.plugin_name)" } else { $tool.binary } { id: $tool.id, binary: $display_name, severity: $tool.severity, present: $present, version: $version, version_min: $tool.version_min, version_ok: $version_ok, config_ok: $config_ok, status: (if not $present { "MISSING" } else if not $version_ok { "VERSION_LOW" } else if not $config_ok { "CONFIG_FAIL" } else { "OK" }), install_hint: $tool.install_hint, config_hint: ($tool.config_hint? | default ""), } } if $json { $results | to json return } print $"Environment check — context: ($context)" print $"─────────────────────────────────────────────────────" let fails = $results | where status != "OK" for r in $results { let icon = match $r.status { "OK" => "✓", "MISSING" => "✗", "VERSION_LOW" => "↑", "CONFIG_FAIL" => "⚠", _ => "?", } let sev = if $r.severity == "Hard" { "[Hard]" } else { "[Soft]" } print $"($icon) ($sev) ($r.binary) ($r.version) [min: ($r.version_min)]" } print "" if ($fails | is-empty) { print "All checks passed." return } let hard_fails = $fails | where severity == "Hard" for f in $fails { print $"── ($f.binary) — ($f.status) ──" match $f.status { "MISSING" => { print $" Install: ($f.install_hint)" }, "VERSION_LOW" => { print $" Installed: ($f.version) Required: >= ($f.version_min)" ; print $" Update: ($f.install_hint)" }, "CONFIG_FAIL" => { print $" Config issue: ($f.config_hint)" }, } print "" } if ($hard_fails | is-not-empty) { let hard_ids = $hard_fails | get binary | str join ", " error make { msg: $"Hard prerequisites not met: ($hard_ids)" } } }