349 lines
10 KiB
Plaintext
Raw Permalink Normal View History

2026-03-13 00:21:04 +00:00
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 <id> switch to an operational mode (run pre/post activate)
# manifest mode list list available operational modes
# manifest publish <service-id> 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<string>, 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 }
}
}