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
|
|
|
# VCS abstraction — detects jj or git from filesystem, exposes uniform operations.
|
|
|
|
|
#
|
|
|
|
|
# All ontoref modules should call these functions instead of hardcoding `git`
|
|
|
|
|
# commands. Detection is filesystem-based (no config, no env var): checks for
|
|
|
|
|
# `.jj/` (jj) and `.git/` (git) in ONTOREF_PROJECT_ROOT or ONTOREF_ROOT.
|
|
|
|
|
|
|
|
|
|
use ./env.nu
|
|
|
|
|
|
|
|
|
|
# Private: resolve project root following the same convention as other modules.
|
|
|
|
|
def project-root []: nothing -> string {
|
|
|
|
|
let pr = ($env.ONTOREF_PROJECT_ROOT? | default "")
|
|
|
|
|
if ($pr | is-not-empty) and ($pr != $env.ONTOREF_ROOT) { $pr } else { $env.ONTOREF_ROOT }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Detect which VCS is active in the project root.
|
|
|
|
|
# Returns: "jj" | "git" | "none"
|
|
|
|
|
export def detect []: nothing -> string {
|
|
|
|
|
let root = (project-root)
|
|
|
|
|
let has_jj = ($root | path join ".jj" | path exists)
|
|
|
|
|
let has_git = ($root | path join ".git" | path exists)
|
|
|
|
|
if $has_jj { "jj" } else if $has_git { "git" } else { "none" }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# True when any VCS is active.
|
|
|
|
|
export def "is-repo" []: nothing -> bool {
|
|
|
|
|
(detect) != "none"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Get file content at last-committed state.
|
|
|
|
|
#
|
|
|
|
|
# jj model: the working copy IS a commit (@). Reading from @- gives the parent
|
|
|
|
|
# commit — i.e., the state before any current working-copy edits.
|
|
|
|
|
# `jj file show` requires jj >= 0.40.
|
|
|
|
|
export def "show-committed" [file_path: string]: nothing -> string {
|
|
|
|
|
let root = (project-root)
|
|
|
|
|
match (detect) {
|
|
|
|
|
"jj" => {
|
|
|
|
|
let rel = ($file_path | path relative-to $root)
|
|
|
|
|
do { ^jj --no-pager --repository $root file show $rel -r "@-" } | complete
|
|
|
|
|
| if $in.exit_code == 0 { $in.stdout } else { "" }
|
|
|
|
|
},
|
|
|
|
|
"git" => {
|
|
|
|
|
let rel = ($file_path | path relative-to $root)
|
|
|
|
|
do { ^git -C $root show $"HEAD:($rel)" } | complete
|
|
|
|
|
| if $in.exit_code == 0 { $in.stdout } else { "" }
|
|
|
|
|
},
|
|
|
|
|
_ => { "" }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Revert a file to its last-committed state.
|
|
|
|
|
#
|
|
|
|
|
# jj: `jj restore --from @-` undoes working-copy edits for the given file.
|
|
|
|
|
# git: `git checkout -- <file>` restores from HEAD.
|
|
|
|
|
export def "restore-file" [file_path: string]: nothing -> nothing {
|
|
|
|
|
let root = (project-root)
|
|
|
|
|
match (detect) {
|
|
|
|
|
"jj" => {
|
|
|
|
|
let rel = ($file_path | path relative-to $root)
|
|
|
|
|
do { ^jj --no-pager --repository $root restore --from "@-" -- $rel } | complete | ignore
|
|
|
|
|
},
|
|
|
|
|
"git" => {
|
|
|
|
|
do { ^git -C $root checkout -- $file_path } | complete | ignore
|
|
|
|
|
},
|
|
|
|
|
_ => {
|
|
|
|
|
error make { msg: $"vcs restore-file: no VCS at ($root)" }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Get the remote origin URL.
|
|
|
|
|
export def "remote-url" []: nothing -> string {
|
|
|
|
|
let root = (project-root)
|
|
|
|
|
match (detect) {
|
|
|
|
|
"jj" => {
|
|
|
|
|
let r = do { ^jj --no-pager --repository $root git remote list } | complete
|
|
|
|
|
if $r.exit_code != 0 or ($r.stdout | str trim | is-empty) { return "" }
|
|
|
|
|
# Format: "<name> <url>" per line — extract URL from first remote
|
|
|
|
|
$r.stdout | lines | where { |l| ($l | str trim | is-not-empty) }
|
|
|
|
|
| first | split row "\t" | last | str trim
|
|
|
|
|
},
|
|
|
|
|
"git" => {
|
|
|
|
|
let r = do { ^git -C $root remote get-url origin } | complete
|
|
|
|
|
if $r.exit_code == 0 { $r.stdout | str trim } else { "" }
|
|
|
|
|
},
|
|
|
|
|
_ => { "" }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Get the current branch or bookmark name.
|
|
|
|
|
#
|
|
|
|
|
# jj: returns the bookmark pointing to @, or "detached" if none.
|
|
|
|
|
# git: returns the branch name from rev-parse.
|
|
|
|
|
export def "current-ref" []: nothing -> string {
|
|
|
|
|
let root = (project-root)
|
|
|
|
|
match (detect) {
|
|
|
|
|
"jj" => {
|
|
|
|
|
let r = do {
|
2026-04-08 00:11:29 +01:00
|
|
|
^jj --no-pager --repository $root bookmark list --pointing-to "@" -T "name ++ \"\\n\""
|
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
|
|
|
} | complete
|
|
|
|
|
if $r.exit_code != 0 { return "detached" }
|
|
|
|
|
let names = ($r.stdout | lines | where { |l| ($l | str trim | is-not-empty) })
|
|
|
|
|
if ($names | is-empty) { "detached" } else { $names | first }
|
|
|
|
|
},
|
|
|
|
|
"git" => {
|
|
|
|
|
let r = do { ^git -C $root rev-parse --abbrev-ref HEAD } | complete
|
|
|
|
|
if $r.exit_code == 0 { $r.stdout | str trim } else { "unknown" }
|
|
|
|
|
},
|
|
|
|
|
_ => { "unknown" }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# True when the project root has a VCS remote configured.
|
|
|
|
|
export def "has-remote" []: nothing -> bool {
|
|
|
|
|
(remote-url) | is-not-empty
|
|
|
|
|
}
|