ontoref/domains/provisioning/commands.nu
Jesús Pérez 472952e29b
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
feat: domain extension system, VCS abstraction, personal/provisioning domains, web subpages
Domain extension system (ADR-012): bash-layer dispatch activates repo_kind-conditional CLI
  domains. install.nu copies domains/ tree; short_alias wrappers generated (personal, prov).
  ore help and describe capabilities domain-aware.

  personal domain (PersonalOntology): career skills/talks/publications/positioning, CFP
  pipeline (Watching→Delivered), opportunities lifecycle, content pipeline, Sessionize
  integration. Daemon pages: /career, /personal.

  provisioning domain (DevWorkspace/Mixed): FSM state, next transitions, connections graph,
  gates, workspace card, capabilities, backlog. Daemon page: /provisioning.

  VCS abstraction layer (ADR-013): reflection/modules/vcs.nu — uniform jj/git API via
  filesystem detection (.jj/ vs .git/). opmode.nu and git-event.nu migrated off ^git.
  reflection/bin/jjw.nu — jj + ontoref + Radicle agent workspace lifecycle. jjw-ncl-merge.nu
  registered as jj merge tool for .ontology/ NCL conflicts. init-repo.nu for new_project mode.
  jj/rad not in ontoref requirements — belong in orchestration project manifests.

  'Framework RepoKind: ontology/schemas/manifest.ncl gains 'Framework variant; ontoref
  self-identifies as framework — no domain activates for the protocol itself.

  Web presence: personal.html and provisioning.html domain subpages. index.html gains
  "Project Types — Domain Extensions" section with type cards and subpage links. Nav
  compacted (Arch/Prov labels, solid backdrop-filter background).

  on+re: vcs-abstraction (adrs: adr-013) and agent-workspace-orchestration Practice nodes;
  21 manifest capabilities; state.ncl catalysts updated.
2026-04-07 23:08:29 +01:00

220 lines
9.2 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env nu
# domains/provisioning/commands.nu — Provisioning domain CLI for ontoref.
# Dispatched by the ontoref bash wrapper when repo_kind in {DevWorkspace, Mixed}:
# ore provisioning <command> [args]
#
# Works for both DevWorkspace (workspace-level) and Mixed (platform-level) projects.
# Commands that require project-specific files (card.ncl, reflection/backlog.ncl)
# degrade gracefully when those files are absent.
def project-root [] {
$env.ONTOREF_PROJECT_ROOT? | default (pwd | path expand)
}
# ─── Loaders ──────────────────────────────────────────────────────────────────
def load-state [] { ^nickel export $"(project-root)/.ontology/state.ncl" | from json }
def load-core [] { ^nickel export $"(project-root)/.ontology/core.ncl" | from json }
def load-gate [] { ^nickel export $"(project-root)/.ontology/gate.ncl" | from json }
def load-connections [] { ^nickel export $"(project-root)/.ontology/connections.ncl" | from json }
def load-manifest [] { ^nickel export $"(project-root)/.ontology/manifest.ncl" | from json }
def load-card [] {
let path = $"(project-root)/card.ncl"
if ($path | path exists) { ^nickel export $path | from json } else { null }
}
def load-backlog [] {
let path = $"(project-root)/reflection/backlog.ncl"
if ($path | path exists) { ^nickel export $path | from json } else { { items: [] } }
}
# ─── state / next / validate ──────────────────────────────────────────────────
export def "state" [] {
load-state | get dimensions | each { |dim|
{ dimension: $dim.id, current: $dim.current_state, desired: $dim.desired_state, horizon: $dim.horizon }
}
}
export def "next" [] {
load-state | get dimensions | each { |dim|
let active = $dim.transitions | where from == $dim.current_state
if ($active | is-empty) {
{ dimension: $dim.id, from: $dim.current_state, to: "", condition: "no active transition", blocker: "", catalyst: "" }
} else {
let tr = $active | first
{ dimension: $dim.id, from: $tr.from, to: $tr.to, condition: $tr.condition, blocker: $tr.blocker, catalyst: $tr.catalyst }
}
}
}
export def "validate" [decision: string] {
let core = load-core
let words = ($decision | str downcase | split row " " | where { |w| ($w | str length) > 3 })
let affected = ($core.nodes | each { |n|
let text = $"($n.id) ($n.name) ($n.description)" | str downcase
if ($words | any { |w| $text =~ $w }) { $n } else { null }
} | compact)
{
decision: $decision,
invariants_at_risk: ($affected | where invariant == true | select id level name),
tensions_touched: ($affected | where level == "Tension" | select id name),
practices_touched: ($affected | where level == "Practice" | select id name),
verdict: "manual review required — if any invariant is contradicted, justification is required",
}
}
# ─── connections / gates ──────────────────────────────────────────────────────
export def "connections" [] {
let c = load-connections
if ($c.upstream? | default [] | is-not-empty) {
print ""
print "UPSTREAM"
$c.upstream | each { |u|
print $" ($u.project) kind=($u.kind) via=($u.via)"
if ($u.node? | default "" | is-not-empty) { print $" node: ($u.node)" }
print $" ($u.note)"
}
}
if ($c.downstream? | default [] | is-not-empty) {
print ""
print "DOWNSTREAM"
$c.downstream | each { |d|
print $" ($d.project) kind=($d.kind) via=($d.via)"
if ($d.node? | default "" | is-not-empty) { print $" node: ($d.node)" }
print $" ($d.note)"
}
}
if ($c.peers? | default [] | is-not-empty) {
print ""
print "PEERS"
$c.peers | each { |p| print $" ($p.project) kind=($p.kind) via=($p.via)" }
}
}
export def "gates" [] {
load-gate | get membranes | each { |m|
{
membrane: $m.id,
name: $m.name,
active: $m.active,
permeability: $m.permeability,
condition: ($m.opening_condition.description? | default ""),
}
}
}
# ─── card (DevWorkspace only) ─────────────────────────────────────────────────
export def "card" [] {
let c = load-card
if ($c | is-empty) {
print "No card.ncl found — this command is only available for DevWorkspace projects."
return
}
print $"id: ($c.id)"
print $"name: ($c.name)"
print $"tagline: ($c.tagline)"
print $"status: ($c.status)"
print $"version: ($c.version)"
print $"started: ($c.started_at)"
if ($c.tags? | default [] | is-not-empty) { print $"tags: ($c.tags | str join ', ')" }
if ($c.tools? | default [] | is-not-empty) { print $"tools: ($c.tools | str join ', ')" }
if ($c.features? | default [] | is-not-empty) {
print ""
print "features:"
$c.features | each { |f| print $" - ($f)" }
}
}
# ─── capabilities (manifest.capabilities) ────────────────────────────────────
export def "capabilities" [] {
let caps = load-manifest | get capabilities? | default []
if ($caps | is-empty) { print "No capabilities declared in manifest."; return }
$caps | select id name summary
}
# ─── backlog (platform only) ──────────────────────────────────────────────────
export def "backlog" [--priority: string = ""] {
let items = load-backlog | get items
if ($items | is-empty) {
print "No backlog.ncl found — this command is only available for platform projects."
return
}
let filtered = if ($priority | is-empty) { $items } else { $items | where priority == $priority }
$filtered | each { |i|
{
id: $i.id,
priority: $i.priority,
blocked_by: ($i.blocked_by | str join ", "),
}
}
}
export def "backlog show" [id: string] {
let items = load-backlog | get items
if ($items | is-empty) { error make { msg: "No backlog.ncl found for this project." } }
let item = $items | where id == $id
if ($item | is-empty) { error make { msg: $"Backlog item not found: ($id)" } }
let r = $item | first
print $"id: ($r.id)"
print $"priority: ($r.priority)"
print ""
print "description:"
print $" ($r.description)"
if ($r.blocked_by? | default [] | is-not-empty) {
print ""
print $"blocked_by: ($r.blocked_by | str join ', ')"
}
if ($r.related_nodes? | default [] | is-not-empty) {
print $"nodes: ($r.related_nodes | str join ', ')"
}
}
# ─── help + main ──────────────────────────────────────────────────────────────
def show-help [] {
print "Provisioning — ontoref domain extension"
print ""
print "USAGE"
print " ore provisioning <command> [args]"
print ""
print "COMMANDS (all repo_kinds)"
print " state Current FSM position across all dimensions"
print " next Next valid transitions with blockers/catalysts"
print " validate <decision> Check against ontological invariants"
print " connections Upstream/downstream project dependency graph"
print " gates Membrane status and opening conditions"
print " capabilities Platform capabilities from manifest"
print ""
print "COMMANDS (DevWorkspace only)"
print " card Workspace card: identity, clusters, status"
print ""
print "COMMANDS (Mixed/platform only)"
print " backlog [--priority] Backlog items filtered by High|Medium|Low"
print " backlog show <id> Full detail of a backlog item"
}
def main [
...args: string
--priority: string = ""
] {
if ($args | is-empty) or ($args | first) == "help" { show-help; return }
let sub = ($args | str join " ")
match $sub {
"state" => { state }
"next" => { next }
"connections" => { connections }
"gates" => { gates }
"card" => { card }
"capabilities" => { capabilities }
"backlog" => { backlog --priority $priority }
_ if ($sub | str starts-with "backlog show ") => { backlog show ($args | get 2) }
_ if ($sub | str starts-with "validate ") => { validate ($args | skip 1 | str join " ") }
_ => { print $"Unknown command: ($sub)"; show-help }
}
}