use store.nu [daemon-export] # Manifest operations — operational modes and publication services. # # Reads $ONTOREF_PROJECT_ROOT/.ontology/manifest.ncl to determine: # - layers, operational_modes, consumption_modes, publication_services # # Commands: # manifest load export and parse the project manifest # manifest mode switch to an operational mode (run pre/post activate) # manifest mode list list available operational modes # manifest publish run a publication workflow # manifest publish list list available publication services # manifest layers show layers with committed status # manifest consumers show consumption modes def manifest-path []: nothing -> string { let root = if ($env.ONTOREF_PROJECT_ROOT? | is-not-empty) { $env.ONTOREF_PROJECT_ROOT } else { $env.PWD } $"($root)/.ontology/manifest.ncl" } # Export and parse the project manifest NCL export def "manifest load" []: nothing -> record { let path = (manifest-path) if not ($path | path exists) { error make { msg: $"No manifest at ($path) — create .ontology/manifest.ncl first" } } # Build import path: project .ontology/ + ontoref ontology/ + existing NICKEL_IMPORT_PATH let project_ontology = ($path | path dirname) let ontoref_ontology = if ($env.ONTOREF_ROOT? | is-not-empty) { $"($env.ONTOREF_ROOT)/ontology" } else { "" } let extra_paths = ([$project_ontology, $ontoref_ontology] | where { $in | is-not-empty }) let existing = ($env.NICKEL_IMPORT_PATH? | default "") let import_path = if ($existing | is-not-empty) { ($extra_paths | append ($existing | split row ":") | uniq | str join ":") } else { ($extra_paths | str join ":") } daemon-export $path --import-path $import_path } # Find an operational mode by id def find-mode [manifest: record, id: string]: nothing -> record { let modes = ($manifest.operational_modes? | default []) let found = ($modes | where { ($in.id? | default "") == $id }) if ($found | is-empty) { let available = ($modes | each { $in.id? | default "?" } | str join ", ") error make { msg: $"Mode '($id)' not found. Available: ($available)" } } $found | first } # Find a publication service by id def find-service [manifest: record, id: string]: nothing -> record { let services = ($manifest.publication_services? | default []) let found = ($services | where { ($in.id? | default "") == $id }) if ($found | is-empty) { let available = ($services | each { $in.id? | default "?" } | str join ", ") error make { msg: $"Service '($id)' not found. Available: ($available)" } } $found | first } # Run a list of shell commands sequentially, abort on failure def run-commands [commands: list, label: string]: nothing -> bool { for cmd in $commands { print $" [$label] ($cmd)" let result = (do { nu -c $cmd } | complete) if $result.exit_code != 0 { print $" [$label] FAILED: ($cmd)" if ($result.stderr | is-not-empty) { print $" ($result.stderr | lines | first 5 | str join '\n ')" } return false } print $" [$label] OK" } true } # Switch to an operational mode — runs pre_activate, shows status, runs post_activate export def "manifest mode" [ id: string # Mode id: dev, publish, investigate, ci --dry-run (-n) # Show what would happen without executing ]: nothing -> record { let m = (manifest load) let mode = (find-mode $m $id) let layers = ($m.layers? | default []) let visible = ($mode.visible_layers? | default []) let hidden = ($layers | where { not ($in.id in $visible) } | each { $in.id }) print "" print $"── Mode: ($mode.id) ──" if ($mode.description? | is-not-empty) { print $" ($mode.description)" } print "" print $" Audit level: ($mode.audit_level)" print $" Visible layers: ($visible | str join ', ')" if ($hidden | is-not-empty) { print $" Hidden layers: ($hidden | str join ', ')" } let pre = ($mode.pre_activate? | default []) let post = ($mode.post_activate? | default []) if $dry_run { if ($pre | is-not-empty) { print "" print " Would run pre_activate:" for cmd in $pre { print $" ($cmd)" } } if ($post | is-not-empty) { print "" print " Would run post_activate:" for cmd in $post { print $" ($cmd)" } } print "" return { mode: $id, status: "dry-run", pre_ok: true, post_ok: true } } mut pre_ok = true if ($pre | is-not-empty) { print "" print " pre_activate:" $pre_ok = (run-commands $pre "pre") if not $pre_ok { print "" print $" Mode activation ABORTED — pre_activate failed." print $" Fix the issues and retry: ontoref mode ($id)" return { mode: $id, status: "failed", pre_ok: false, post_ok: false } } } mut post_ok = true if ($post | is-not-empty) { print "" print " post_activate:" $post_ok = (run-commands $post "post") if not $post_ok { print "" print $" WARNING: post_activate failed. Mode is active but not fully verified." } } let status = if $pre_ok and $post_ok { "active" } else { "partial" } print "" print $" Mode '($id)' → ($status)" { mode: $id, status: $status, pre_ok: $pre_ok, post_ok: $post_ok } } # List available operational modes export def "manifest mode list" [ --fmt: string = "table" # Output format: table | json ]: nothing -> table { let m = (manifest load) let modes = ($m.operational_modes? | default []) let default_mode = ($m.default_mode? | default "dev") let rows = ($modes | each {|mode| { id: $mode.id, description: ($mode.description? | default ""), audit: ($mode.audit_level? | default "Standard"), layers: ($mode.visible_layers? | default [] | length), pre: ($mode.pre_activate? | default [] | length), post: ($mode.post_activate? | default [] | length), default: ($mode.id == $default_mode), } }) match $fmt { "json" => { $rows | to json } _ => { $rows } } } # Run a publication workflow — pre_publish, confirmation, post_publish export def "manifest publish" [ id: string # Service id: crates-io-public, gitea-private, etc. --dry-run (-n) # Show what would happen without executing --yes (-y) # Skip confirmation prompt ]: nothing -> record { let m = (manifest load) let svc = (find-service $m $id) print "" print $"── Publish: ($svc.id) ──" print $" Artifact: ($svc.artifact)" print $" Scope: ($svc.scope)" if ($svc.registry_url? | is-not-empty) { print $" Registry: ($svc.registry_url)" } print $" Auth: ($svc.auth_method)" print $" Trigger: ($svc.trigger)" if ($svc.condition? | is-not-empty) { print $" Condition: ($svc.condition)" } let pre = ($svc.pre_publish? | default []) let post = ($svc.post_publish? | default []) if $dry_run { if ($pre | is-not-empty) { print "" print " Would run pre_publish:" for cmd in $pre { print $" ($cmd)" } } print "" print " Would execute publish action" if ($post | is-not-empty) { print "" print " Would run post_publish:" for cmd in $post { print $" ($cmd)" } } print "" return { service: $id, status: "dry-run" } } # Pre-publish checks mut pre_ok = true if ($pre | is-not-empty) { print "" print " pre_publish:" $pre_ok = (run-commands $pre "pre") if not $pre_ok { print "" print $" Publish ABORTED — pre_publish failed." return { service: $id, status: "failed", stage: "pre_publish" } } } # Confirmation gate if not $yes { print "" let answer = (input $" Proceed with publish to ($svc.id)? [y/n] ") if not ($answer | str starts-with "y") { print " Publish cancelled." return { service: $id, status: "cancelled" } } } # Post-publish actions mut post_ok = true if ($post | is-not-empty) { print "" print " post_publish:" $post_ok = (run-commands $post "post") if not $post_ok { print "" print " WARNING: post_publish failed. Publish may have succeeded but follow-up actions incomplete." } } let status = if $pre_ok and $post_ok { "published" } else { "partial" } print "" print $" Service '($id)' → ($status)" { service: $id, status: $status } } # List available publication services export def "manifest publish list" [ --fmt: string = "table" ]: nothing -> table { let m = (manifest load) let services = ($m.publication_services? | default []) let rows = ($services | each {|svc| { id: $svc.id, artifact: ($svc.artifact? | default ""), scope: ($svc.scope? | default ""), auth: ($svc.auth_method? | default "None"), trigger: ($svc.trigger? | default ""), pre: ($svc.pre_publish? | default [] | length), post: ($svc.post_publish? | default [] | length), } }) match $fmt { "json" => { $rows | to json } _ => { $rows } } } # Show all layers with their visibility status export def "manifest layers" [ --mode (-m): string = "" # Show visibility for a specific mode ]: nothing -> table { let m = (manifest load) let layers = ($m.layers? | default []) if ($mode | is-not-empty) { let op_mode = (find-mode $m $mode) let visible = ($op_mode.visible_layers? | default []) $layers | each {|l| { id: $l.id, committed: $l.committed, visible: ($l.id in $visible), paths: ($l.paths | str join ", "), description: ($l.description? | default ""), } } } else { $layers | each {|l| { id: $l.id, committed: $l.committed, paths: ($l.paths | str join ", "), description: ($l.description? | default ""), } } } } # Show consumption modes — who consumes and what they need export def "manifest consumers" [ --fmt: string = "table" ]: nothing -> table { let m = (manifest load) let consumers = ($m.consumption_modes? | default []) let rows = ($consumers | each {|c| { consumer: ($c.consumer? | default ""), needs: ($c.needs? | default [] | str join ", "), audit: ($c.audit_level? | default "Standard"), description: ($c.description? | default ""), } }) match $fmt { "json" => { $rows | to json } _ => { $rows } } }