Jesús Pérez 0396e4037b
Some checks failed
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
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
chore: add ontology and reflection
2026-03-13 00:21:04 +00:00

203 lines
7.2 KiB
Plaintext

#!/usr/bin/env nu
# reflection/modules/forms.nu — form listing and execution.
#
# Error handling policy:
# forms list — daemon-export-safe; graceful skip on broken form file
# form run — daemon-export (fail loud); agent path renders NCL template via tera
# render-* — tera-render direct; fail loud on template error
use env.nu *
use store.nu [daemon-export, daemon-export-safe]
export def "forms list" [] {
form-files | each { |f|
let data = (daemon-export-safe $f)
if $data != null {
{
name: ($f | path basename | str replace ".ncl" ""),
description: ($data.description? | default ""),
}
} else { null }
} | compact
}
export def "form run" [
name: string,
--backend: string = "cli", # Backend: cli (default) | tui | web
] {
let actor = ($env.ONTOREF_ACTOR? | default "developer")
let forms_dir = $"($env.ONTOREF_ROOT)/reflection/forms"
let form_file = $"($forms_dir)/($name).ncl"
# Guard: form must exist
if not ($form_file | path exists) {
let available = (form-files | each { |f| $f | path basename | str replace ".ncl" "" })
print $"Form '($name)' not found."
print $"Available: ($available | str join ', ')"
exit 1
}
if $actor == "agent" {
agent-render $name $form_file
return
}
# Guard: typedialog must be present for interactive path
if (which typedialog | is-empty) {
print ""
print "typedialog is required for interactive forms."
print "Install: cargo install typedialog"
print ""
print "Agent path (no typedialog needed):"
agent-render-hint $name $form_file
exit 1
}
run-interactive-form $name $form_file $backend
}
# Render an ADR from a piped record via tera-render.
# { id: "adr-005", title: "...", status: "Proposed" } | form render-adr | save adrs/adr-005-title.ncl
export def "form render-adr" [
--output: path,
] {
let tmpl = $"($env.ONTOREF_ROOT)/reflection/templates/adr.ncl.j2"
let rendered = $in | tera-render $tmpl
if ($output | is-not-empty) {
$rendered | save --force $output
print $"Written: ($output)"
} else {
$rendered
}
}
# Render a new-project script from a piped record via tera-render.
# { project_name: "myapp", project_dir: "/tmp/myapp" } | form render-project --output ~/create.nu
export def "form render-project" [
--output: path,
] {
let tmpl = $"($env.ONTOREF_ROOT)/reflection/templates/create_project.nu.j2"
let rendered = $in | tera-render $tmpl
if ($output | is-not-empty) {
$rendered | save --force $output
print $"Written: ($output)"
} else {
$rendered
}
}
export def "forms help" [] {
let actor = ($env.ONTOREF_ACTOR? | default "developer")
print ""
print "Form commands:"
print " forms list list available forms"
print " form run <name> run a form (interactive or agent)"
print " form render-adr [--output <path>] render ADR from piped record"
print " form render-project [--output] render new-project script from piped record"
print ""
for f in (forms list) {
print $" ($f.name)"
print $" ($f.description)"
}
if $actor == "agent" {
print ""
print "Agent render pipeline:"
print " nickel-export adrs/_template.ncl | form render-adr --output adrs/adr-005-title.ncl"
print " { project_name: 'myapp', ... } | form render-project --output ~/create.nu"
print ""
print "Inspect form fields:"
print " nickel-export reflection/forms/<name>.ncl | get elements"
print " | where type != 'section_header' | select name prompt required nickel_path"
}
print ""
}
# ── Internal ───────────────────────────────────────────────────────────────────
def form-files [] {
glob $"($env.ONTOREF_ROOT)/reflection/forms/*.ncl"
}
def next-adr-id [] {
let root = ($env.ONTOREF_PROJECT_ROOT? | default $env.ONTOREF_ROOT)
let nums = (
glob $"($root)/adrs/adr-*.ncl"
| each { |f| $f | path basename }
| parse "adr-{n}-{rest}.ncl"
| get n
| each { |n| $n | into int }
| sort
)
let next = if ($nums | is-empty) { 1 } else { ($nums | last) + 1 }
$"adr-($next | fill --alignment right --width 3 --character '0')"
}
def agent-render [name: string, form_file: string] {
if $name == "new_adr" {
let root = ($env.ONTOREF_PROJECT_ROOT? | default $env.ONTOREF_ROOT)
let template = $"($env.ONTOREF_ROOT)/adrs/_template.ncl"
let tmpl = $"($env.ONTOREF_ROOT)/reflection/templates/adr.ncl.j2"
let next_id = (next-adr-id)
let out = $"($root)/adrs/($next_id)-draft.ncl"
print $"Rendering ($next_id) from template — output: ($out)"
daemon-export $template | to json | tera-render $tmpl | save --force $out
print $"Run: nickel-validate ($out)"
} else {
agent-render-hint $name $form_file
}
}
def agent-render-hint [name: string, form_file: string] {
print ""
print $"Fields for '($name)':"
print $" nickel-export ($form_file) | get elements"
print " | where type != \"section_header\" | select name prompt required nickel_path"
print ""
}
def td-roundtrip [backend: string, input: string, form: string, output: string, ncl_template: string] {
match $backend {
"web" => { ^typedialog web nickel-roundtrip $input $form --output $output --ncl-template $ncl_template --open },
"tui" => { ^typedialog tui nickel-roundtrip $input $form --output $output --ncl-template $ncl_template },
_ => { ^typedialog nickel-roundtrip $input $form --output $output --ncl-template $ncl_template },
}
}
def td-form [backend: string, form: string, ...extra: string] {
match $backend {
"web" => { ^typedialog web form $form ...$extra },
"tui" => { ^typedialog tui $form ...$extra },
_ => { ^typedialog form $form ...$extra },
}
}
def run-interactive-form [name: string, form_file: string, backend: string] {
if $name == "new_adr" {
let root = ($env.ONTOREF_PROJECT_ROOT? | default $env.ONTOREF_ROOT)
let template = $"($env.ONTOREF_ROOT)/adrs/_template.ncl"
let tmpl = $"($env.ONTOREF_ROOT)/reflection/templates/adr.ncl.j2"
let next_id = (next-adr-id)
let out = $"($root)/adrs/($next_id)-draft.ncl"
let tmp = $"($env.HOME)/.ontoref-adr-tmp.ncl"
open $template | str replace '"adr-000"' $'"($next_id)"' | save --force $tmp
print $"Creating ($next_id) — output: ($out)"
td-roundtrip $backend $tmp $form_file $out $tmpl
rm --force $tmp
print $"Run: nickel typecheck ($out)"
} else if $name == "new_project" {
let tmpl = $"($env.ONTOREF_ROOT)/reflection/templates/create_project.nu.j2"
let out = $"($env.HOME)/ontoref-create-project.nu"
td-form $backend $form_file "--ncl-template" $tmpl "--output" $out
print $"Script generated: ($out)"
print $"Review then: nu ($out)"
} else if $name == "supersede_adr" {
let tmpl = $"($env.ONTOREF_ROOT)/reflection/templates/supersede_adr.nu.j2"
let out = $"($env.HOME)/ontoref-supersede.nu"
td-form $backend $form_file "--ncl-template" $tmpl "--output" $out
print $"Script generated: ($out)"
print $"Review then: nu ($out)"
} else {
td-form $backend $form_file
}
}