From bd5e5c64a3199e7d8f887e1ccf0543a47c9a69cf Mon Sep 17 00:00:00 2001 From: KiKaraage Date: Wed, 16 Sep 2026 20:36:18 +0700 Subject: [PATCH 1/7] feat(bling): add tailored ujust bash/zsh/fish completions Read justfile & flags file, register it as completion with recipes for all three shells. Also declare 'local justfile' override for testing with bats https://opncd.ai/share/HiYO5BRh Assisted-by: Muse Spark 1.3 in OpenCode --- .../share/bash-completion/completions/ujust | 41 ++++++++++++ .../fish/vendor_completions.d/ujust.fish | 36 ++++++++++ .../usr/share/ublue-os/just/ujust-flags | 67 +++++++++++++++++++ .../usr/share/zsh/site-functions/_ujust | 39 +++++++++++ 4 files changed, 183 insertions(+) create mode 100644 system_files/shared/usr/share/bash-completion/completions/ujust create mode 100644 system_files/shared/usr/share/fish/vendor_completions.d/ujust.fish create mode 100644 system_files/shared/usr/share/ublue-os/just/ujust-flags create mode 100644 system_files/shared/usr/share/zsh/site-functions/_ujust diff --git a/system_files/shared/usr/share/bash-completion/completions/ujust b/system_files/shared/usr/share/bash-completion/completions/ujust new file mode 100644 index 00000000..4b5d2e94 --- /dev/null +++ b/system_files/shared/usr/share/bash-completion/completions/ujust @@ -0,0 +1,41 @@ +# bash completion for ujust +# +# Flags come from the ujust-flags data file shipped next to the entry +# justfile (one flag per line). When `just --help` gains flags, update the +# data file — the completions read it at TAB time, no per-shell edits needed. + +_ujust() { + local cur words cword + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion || return + else + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + words=("${COMP_WORDS[@]}") + cword="${COMP_CWORD}" + fi + + # UJUST_JUSTFILE / UJUST_FLAGS_FILE overrides exist for testing; + # defaults are the image entry justfile and the flags list next to it. + local justfile="${UJUST_JUSTFILE:-/usr/share/ublue-os/just/00-entry.just}" + local flags_file="${UJUST_FLAGS_FILE:-${justfile%/*}/ujust-flags}" + + if [[ "${cur}" == -* ]]; then + local flags=() + if [[ -f "${flags_file}" ]]; then + mapfile -t flags < "${flags_file}" + fi + COMPREPLY=( $(compgen -W "${flags[*]}" -- "${cur}") ) + return 0 + fi + + # Recipe completion: if just is installed and entry justfile exists, fetch recipe list + if [[ -f "${justfile}" ]] && command -v just >/dev/null 2>&1; then + local recipes + recipes=$(just --summary --justfile "${justfile}" 2>/dev/null) + COMPREPLY=( $(compgen -W "${recipes}" -- "${cur}") ) + return 0 + fi +} + +complete -F _ujust ujust diff --git a/system_files/shared/usr/share/fish/vendor_completions.d/ujust.fish b/system_files/shared/usr/share/fish/vendor_completions.d/ujust.fish new file mode 100644 index 00000000..e45348b8 --- /dev/null +++ b/system_files/shared/usr/share/fish/vendor_completions.d/ujust.fish @@ -0,0 +1,36 @@ +# fish completion for ujust +# +# Flags come from the ujust-flags data file shipped next to the entry +# justfile (one flag per line). When `just --help` gains flags, update the +# data file — the completions read it at TAB time, no per-shell edits needed. + +function __ujust_justfile + # UJUST_JUSTFILE override exists for testing; default is the image entry justfile. + if set -q UJUST_JUSTFILE + echo $UJUST_JUSTFILE + else + echo /usr/share/ublue-os/just/00-entry.just + end +end + +function __ujust_flags_file + # UJUST_FLAGS_FILE override exists for testing; default sits next to the entry justfile. + if set -q UJUST_FLAGS_FILE + echo $UJUST_FLAGS_FILE + else + echo (string replace -r '/[^/]*$' '' (__ujust_justfile))/ujust-flags + end +end + +function __ujust_recipes + just --summary --justfile (__ujust_justfile) 2>/dev/null | tr ' ' '\n' +end + +function __ujust_flags + if test -f (__ujust_flags_file) + cat (__ujust_flags_file) + end +end + +complete -c ujust -f -a '(__ujust_recipes)' +complete -c ujust -f -a '(__ujust_flags)' diff --git a/system_files/shared/usr/share/ublue-os/just/ujust-flags b/system_files/shared/usr/share/ublue-os/just/ujust-flags new file mode 100644 index 00000000..602916af --- /dev/null +++ b/system_files/shared/usr/share/ublue-os/just/ujust-flags @@ -0,0 +1,67 @@ +--changelog +--check +--choose +--clean +--clear-shell-args +--color +--command +--command-color +--complete-aliases +--completions +--dry-run +--dump +--dump-format +--edit +--evaluate +--evaluate-format +--explain +--fmt +--format +--global-justfile +--groups +--help +--highlight +--init +--jobs +--justfile +--list +--list-heading +--list-prefix +--list-submodules +--man +--no-aliases +--no-deps +--no-dotenv +--no-highlight +--one +--quiet +--set +--shell +--shell-arg +--shell-command +--show +--summary +--timestamp +--unsorted +--unstable +--usage +--variables +--verbose +--version +--working-directory +--yes +-c +-d +-e +-E +-f +-F +-g +-h +-l +-n +-q +-s +-u +-v +-V diff --git a/system_files/shared/usr/share/zsh/site-functions/_ujust b/system_files/shared/usr/share/zsh/site-functions/_ujust new file mode 100644 index 00000000..eb0c6b80 --- /dev/null +++ b/system_files/shared/usr/share/zsh/site-functions/_ujust @@ -0,0 +1,39 @@ +#compdef ujust + +_ujust() { + # UJUST_JUSTFILE override exists for testing; default is the image entry justfile. + local justfile="${UJUST_JUSTFILE:-/usr/share/ublue-os/just/00-entry.just}" + + if (( CURRENT == 2 )); then + # Complete flags from the ujust-flags data file shipped next to + # the entry justfile (one flag per line). Falls through to recipes + # if the data file is missing. + if [[ "${words[CURRENT]}" == -* ]]; then + local flags_file="${UJUST_FLAGS_FILE:-${justfile:h}/ujust-flags}" + if [[ -f "$flags_file" ]]; then + local -a flags + flags=(${(f)"$(<$flags_file)"}) + _describe -t flags 'flag' flags && return 0 + fi + fi + + if [[ -f "$justfile" ]] && (( $+commands[just] )); then + local -a recipes + recipes=(${(f)"$(_call_program recipes just --summary --justfile "$justfile" 2>/dev/null)"}) + # just --summary outputs recipe names separated by spaces + recipes=($=recipes) + if (( $#recipes > 0 )); then + _describe -t recipes 'recipe' recipes && return 0 + fi + fi + fi + + # Fall back to native just completion if available + if (( $+functions[_just] )); then + words=(just --justfile "$justfile" "${words[@]:1}") + (( CURRENT += 2 )) + _just + fi +} + +_ujust "$@" From bc133ca3fe33f857f064eede0698c1f845b8d7a8 Mon Sep 17 00:00:00 2001 From: KiKaraage Date: Wed, 16 Sep 2026 20:43:06 +0700 Subject: [PATCH 2/7] feat(bling): new tests for ujust shell completions Meant for guarding against regression to filename completion. Important, since vendored completions (from common) take priorities over image-defined ones https://opncd.ai/share/HiYO5BRh Assisted-by: Muse Spark 1.3 in OpenCode --- Justfile | 1 + tests/test_ujust_completion.bats | 352 +++++++++++++++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 tests/test_ujust_completion.bats diff --git a/Justfile b/Justfile index f5fcdb4d..135ea2fb 100644 --- a/Justfile +++ b/Justfile @@ -17,6 +17,7 @@ test: bats tests/test_update_just.bats bats tests/test_native_recipes.bats bats tests/test_ujust.bats + bats tests/test_ujust_completion.bats bats tests/test_ublue_fastfetch.bats bats tests/test_motd_integration.bats bats tests/test_clean_system_podman_path.bats diff --git a/tests/test_ujust_completion.bats b/tests/test_ujust_completion.bats new file mode 100644 index 00000000..33cb5991 --- /dev/null +++ b/tests/test_ujust_completion.bats @@ -0,0 +1,352 @@ +#!/usr/bin/env bats +# Tests for ujust shell completions (bash, zsh, fish). +# +# Guards against regression to filename completion +# (projectbluefin/bluefin#1171): the old +# `just --completions | sed 's/just/ujust/'` generator emitted a +# dynamic loader bound to the `just` command name, so TAB after `ujust` +# completed files in the current directory instead of recipes. + +REPO_ROOT="$BATS_TEST_DIRNAME/.." +BASH_COMPLETION="$REPO_ROOT/system_files/shared/usr/share/bash-completion/completions/ujust" +ZSH_COMPLETION="$REPO_ROOT/system_files/shared/usr/share/zsh/site-functions/_ujust" +FISH_COMPLETION="$REPO_ROOT/system_files/shared/usr/share/fish/vendor_completions.d/ujust.fish" +ENTRY_JUSTFILE="/usr/share/ublue-os/just/00-entry.just" +FLAGS_FILE="$REPO_ROOT/system_files/shared/usr/share/ublue-os/just/ujust-flags" +WORKDIR="" + +setup() { + WORKDIR="$(mktemp -d)" + mkdir -p "${WORKDIR}/bin" + : > "${WORKDIR}/calls.log" + # Sandbox justfile and flags file: functional tests point the + # UJUST_JUSTFILE / UJUST_FLAGS_FILE overrides here so they pass on + # hosts without the image paths (e.g. CI runners). + : > "${WORKDIR}/00-entry.just" + printf '%s\n' --list --version -V --verbose > "${WORKDIR}/ujust-flags" + + # Mock `just`: answers --summary with a fixed recipe list and logs + # every invocation so tests can assert the entry justfile is used. + cat > "${WORKDIR}/bin/just" <<'EOF' +#!/usr/bin/bash +printf 'just %s\n' "$*" >> "${CALLS:-/dev/null}" +if [[ " $* " == *" --summary "* ]]; then + echo "update upgrade rollback" + exit 0 +fi +echo "mock-just: unexpected args: $*" >&2 +exit 1 +EOF + chmod +x "${WORKDIR}/bin/just" +} + +teardown() { + rm -rf "${WORKDIR}" +} + +# --------------------------------------------------------------------------- +# Content assertions: the installed files must bind `ujust`, not `just`. +# Existence checks alone pass on the broken loader shims, so assert content. +# --------------------------------------------------------------------------- + +@test "bash completion file binds the ujust command" { + [ -f "${BASH_COMPLETION}" ] + grep -qF "complete -F _ujust ujust" "${BASH_COMPLETION}" + grep -qF "just --summary" "${BASH_COMPLETION}" + grep -qF "UJUST_JUSTFILE" "${BASH_COMPLETION}" +} + +@test "bash completion file is not a just dynamic-loader shim" { + [ -f "${BASH_COMPLETION}" ] + [ "$(grep -cF "JUST_COMPLETE" "${BASH_COMPLETION}" || true)" -eq 0 ] + [ "$(grep -cF "_clap_complete_just" "${BASH_COMPLETION}" || true)" -eq 0 ] +} + +@test "zsh completion file defines a ujust completer" { + [ -f "${ZSH_COMPLETION}" ] + grep -qF "#compdef ujust" "${ZSH_COMPLETION}" + grep -qF "_ujust()" "${ZSH_COMPLETION}" + grep -qF "just --summary" "${ZSH_COMPLETION}" + grep -qF "UJUST_JUSTFILE" "${ZSH_COMPLETION}" +} + +@test "zsh completion file offers flags for dash-prefixed words" { + [ -f "${ZSH_COMPLETION}" ] + grep -qF "ujust-flags" "${ZSH_COMPLETION}" + grep -qF "_describe -t flags" "${ZSH_COMPLETION}" +} + +@test "zsh completion file is not a just dynamic-loader shim" { + [ -f "${ZSH_COMPLETION}" ] + [ "$(grep -cF "JUST_COMPLETE" "${ZSH_COMPLETION}" || true)" -eq 0 ] + [ "$(grep -cF "_clap_dynamic_completer_just" "${ZSH_COMPLETION}" || true)" -eq 0 ] +} + +@test "fish completion file completes the ujust command" { + [ -f "${FISH_COMPLETION}" ] + grep -qF "complete -c ujust" "${FISH_COMPLETION}" + grep -qF "just --summary" "${FISH_COMPLETION}" + grep -qF "UJUST_JUSTFILE" "${FISH_COMPLETION}" +} + +@test "fish completion file offers flags as well as recipes" { + [ -f "${FISH_COMPLETION}" ] + grep -qF "ujust-flags" "${FISH_COMPLETION}" + grep -qF "__ujust_flags" "${FISH_COMPLETION}" +} + +@test "completions default to the image entry justfile" { + grep -qF "${ENTRY_JUSTFILE}" "${BASH_COMPLETION}" + grep -qF "${ENTRY_JUSTFILE}" "${ZSH_COMPLETION}" + grep -qF "${ENTRY_JUSTFILE}" "${FISH_COMPLETION}" +} + +@test "fish completion file is not a just dynamic-loader shim" { + [ -f "${FISH_COMPLETION}" ] + [ "$(grep -cF "JUST_COMPLETE" "${FISH_COMPLETION}" || true)" -eq 0 ] +} + +@test "Containerfile does not generate completions via a just-to-ujust rename" { + [ "$(grep -cF "just --completions" "$REPO_ROOT/Containerfile" || true)" -eq 0 ] +} + +@test "ujust-flags data file lists one flag per line" { + [ -f "${FLAGS_FILE}" ] + grep -qx -- "--version" "${FLAGS_FILE}" + grep -qx -- "-V" "${FLAGS_FILE}" + grep -qx -- "--list" "${FLAGS_FILE}" + [ "$(grep -c '^$' "${FLAGS_FILE}" || true)" -eq 0 ] + [ "$(grep -c '^#' "${FLAGS_FILE}" || true)" -eq 0 ] +} + +@test "completions read flags from the data file instead of embedding lists" { + grep -qF "ujust-flags" "${BASH_COMPLETION}" + grep -qF "ujust-flags" "${ZSH_COMPLETION}" + grep -qF "ujust-flags" "${FISH_COMPLETION}" + ! grep -qF -- "--list-heading" "${BASH_COMPLETION}" "${ZSH_COMPLETION}" "${FISH_COMPLETION}" +} + +# --------------------------------------------------------------------------- +# Functional tests: completions offer recipes from the entry justfile. +# --------------------------------------------------------------------------- + +@test "bash completion offers matching recipes for a prefix" { + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + bash -c ' + source "${BASH_COMPLETION}" + COMP_WORDS=(ujust up) + COMP_CWORD=1 + COMP_LINE="ujust up" + COMP_POINT=8 + COMPREPLY=() + _ujust ujust up "" + printf "%s\n" "${COMPREPLY[@]}" + ' + + [ "${status}" -eq 0 ] + [[ "${output}" == *update* ]] + [[ "${output}" == *upgrade* ]] + [[ "${output}" != *rollback* ]] +} + +@test "bash completion lists all recipes on an empty word" { + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + bash -c ' + source "${BASH_COMPLETION}" + COMP_WORDS=(ujust "") + COMP_CWORD=1 + COMP_LINE="ujust " + COMP_POINT=6 + COMPREPLY=() + _ujust ujust "" "" + printf "%s\n" "${COMPREPLY[@]}" + ' + + [ "${status}" -eq 0 ] + [[ "${output}" == *update* ]] + [[ "${output}" == *upgrade* ]] + [[ "${output}" == *rollback* ]] +} + +@test "bash completion offers flags for a dash-prefixed word" { + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + bash -c ' + source "${BASH_COMPLETION}" + COMP_WORDS=(ujust --l) + COMP_CWORD=1 + COMP_LINE="ujust --l" + COMP_POINT=9 + COMPREPLY=() + _ujust ujust --l "" + printf "%s\n" "${COMPREPLY[@]}" + ' + + [ "${status}" -eq 0 ] + [[ "${output}" == *--list* ]] +} + +@test "bash completion offers -V (version), distinct from -v (verbose)" { + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + bash -c ' + source "${BASH_COMPLETION}" + COMP_WORDS=(ujust -V) + COMP_CWORD=1 + COMP_LINE="ujust -V" + COMP_POINT=8 + COMPREPLY=() + _ujust ujust -V "" + printf "%s\n" "${COMPREPLY[@]}" + ' + + [ "${status}" -eq 0 ] + [[ "${output}" == *-V* ]] +} + +@test "bash completion queries recipes from the entry justfile" { + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" CALLS="${WORKDIR}/calls.log" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + bash -c ' + source "${BASH_COMPLETION}" + COMP_WORDS=(ujust "") + COMP_CWORD=1 + COMP_LINE="ujust " + COMP_POINT=6 + COMPREPLY=() + _ujust ujust "" "" >/dev/null + ' + + [ "${status}" -eq 0 ] + grep -qF "just --summary --justfile ${WORKDIR}/00-entry.just" "${WORKDIR}/calls.log" +} + +@test "bash completion offers nothing when the justfile is missing" { + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/no-such.just" BASH_COMPLETION="${BASH_COMPLETION}" \ + bash -c ' + source "${BASH_COMPLETION}" + COMP_WORDS=(ujust "") + COMP_CWORD=1 + COMP_LINE="ujust " + COMP_POINT=6 + COMPREPLY=() + _ujust ujust "" "" + printf "%s\n" "${COMPREPLY[@]}" + ' + + [ "${status}" -eq 0 ] + [ -z "${output}" ] +} + +@test "bash completion offers no flags when the flags file is missing" { + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/no-such-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ + bash -c ' + source "${BASH_COMPLETION}" + COMP_WORDS=(ujust --l) + COMP_CWORD=1 + COMP_LINE="ujust --l" + COMP_POINT=9 + COMPREPLY=() + _ujust ujust --l "" + printf "%s\n" "${COMPREPLY[@]}" + ' + + [ "${status}" -eq 0 ] + [ -z "${output}" ] +} + +@test "zsh completion lists recipes from the entry justfile" { + [ -n "$(command -v zsh)" ] || skip "zsh not installed" + local out="${WORKDIR}/zsh-recipes.txt" + + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" ZSH_COMPLETION="${ZSH_COMPLETION}" \ + zsh -c ' + _call_program() { local _tag=$1; shift; "$@" } + _describe() { print -r -- "${(P)${@[-1]}}" > "$OUT" } + CURRENT=2 + words=(ujust "") + source "${ZSH_COMPLETION}" + ' + + [ "${status}" -eq 0 ] + grep -qw "update" "${out}" + grep -qw "upgrade" "${out}" + grep -qw "rollback" "${out}" +} + +@test "zsh completion offers flags for a dash-prefixed word" { + [ -n "$(command -v zsh)" ] || skip "zsh not installed" + local out="${WORKDIR}/zsh-flags.txt" + + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" ZSH_COMPLETION="${ZSH_COMPLETION}" \ + zsh -c ' + _call_program() { local _tag=$1; shift; "$@" } + _describe() { print -r -- "${(P)${@[-1]}}" > "$OUT" } + CURRENT=2 + words=(ujust --l) + source "${ZSH_COMPLETION}" + ' + + [ "${status}" -eq 0 ] + grep -qw -- "--list" "${out}" + grep -qw -- "-V" "${out}" + [ "$(grep -cw "update" "${out}" || true)" -eq 0 ] +} + +@test "zsh completion falls back to recipes when the flags file is missing" { + [ -n "$(command -v zsh)" ] || skip "zsh not installed" + local out="${WORKDIR}/zsh-flags-missing.txt" + + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/no-such-flags" ZSH_COMPLETION="${ZSH_COMPLETION}" \ + zsh -c ' + _call_program() { local _tag=$1; shift; "$@" } + _describe() { print -r -- "${(P)${@[-1]}}" > "$OUT" } + CURRENT=2 + words=(ujust --l) + source "${ZSH_COMPLETION}" + ' + + [ "${status}" -eq 0 ] + grep -qw "update" "${out}" +} + +@test "fish completion offers matching recipes for a prefix" { + [ -n "$(command -v fish)" ] || skip "fish not installed" + + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ + fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust up"' + + [ "${status}" -eq 0 ] + [[ "${output}" == *update* ]] + [[ "${output}" == *upgrade* ]] + [[ "${output}" != *rollback* ]] +} + +@test "fish completion lists all recipes on an empty word" { + [ -n "$(command -v fish)" ] || skip "fish not installed" + + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ + fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust "' + + [ "${status}" -eq 0 ] + [[ "${output}" == *update* ]] + [[ "${output}" == *upgrade* ]] + [[ "${output}" == *rollback* ]] +} + +@test "fish completion offers flags for a dash-prefixed word" { + [ -n "$(command -v fish)" ] || skip "fish not installed" + + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ + fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust --l"' + + [ "${status}" -eq 0 ] + [[ "${output}" == *--list* ]] +} + +@test "fish completion offers -V (version)" { + [ -n "$(command -v fish)" ] || skip "fish not installed" + + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" FISH_COMPLETION="${FISH_COMPLETION}" \ + fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust -V"' + + [ "${status}" -eq 0 ] + [[ "${output}" == *-V* ]] +} From 9cd010bf5ae702ff9ee161e57ceab8f2d8937306 Mon Sep 17 00:00:00 2001 From: KiKaraage Date: Wed, 16 Sep 2026 21:39:09 +0700 Subject: [PATCH 3/7] fix: drop just --completions generator, gate the checked-in files https://opncd.ai/share/HiYO5BRh Assisted-by: Muse Spark 1.3 in OpenCode --- Containerfile | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Containerfile b/Containerfile index bb8671b2..0e005d42 100644 --- a/Containerfile +++ b/Containerfile @@ -23,11 +23,6 @@ RUN mkdir -p /out/bluefin/usr/share/backgrounds/bluefin && \ mv /out/bluefin/usr/share/*.jxl /out/bluefin/usr/share/*.xml /out/bluefin/usr/share/backgrounds/bluefin && \ sed -i 's|~\/\.local\/share|\/usr\/share|' /out/bluefin/usr/share/backgrounds/bluefin/*.xml /out/bluefin/usr/share/gnome-background-properties/*.xml -RUN install -d /out/shared/usr/share/bash-completion/completions /out/shared/usr/share/zsh/site-functions /out/shared/usr/share/fish/vendor_completions.d/ && \ - just --completions bash | sed -E 's/([\(_" ])just/\1ujust/g' > /out/shared/usr/share/bash-completion/completions/ujust && \ - just --completions zsh | sed -E 's/([\(_" ])just/\1ujust/g' > /out/shared/usr/share/zsh/site-functions/_ujust && \ - just --completions fish | sed -E 's/([\(_" ])just/\1ujust/g' > /out/shared/usr/share/fish/vendor_completions.d/ujust.fish - # Fetch game-devices-udev rules as individual raw files at a fixed commit SHA. # Codeberg/Gitea archive tarballs are generated on demand and their checksums # drift across infra changes, so per-file raw fetches with sha256 pins are used @@ -83,6 +78,23 @@ RUN set -e && mkdir -p /out/bluefin/etc/bazaar && \ COPY --from=umotd-build /umotd /out/shared/usr/bin/umotd COPY --from=uwelcome-build /uwelcome /out/shared/usr/bin/uwelcome +# Ujust gate: the tailored completions checked into system_files/shared must bind `ujust` +# & /out/shared must not ship files at the same paths to avoid shadow by ctx overlay. +COPY system_files/shared/usr/share/bash-completion/completions/ujust \ + system_files/shared/usr/share/zsh/site-functions/_ujust \ + system_files/shared/usr/share/fish/vendor_completions.d/ujust.fish \ + system_files/shared/usr/share/ublue-os/just/ujust-flags \ + /tmp/ujust-gate/ +RUN set -e; \ + grep -qF 'complete -F _ujust ujust' /tmp/ujust-gate/ujust; \ + grep -qF '#compdef ujust' /tmp/ujust-gate/_ujust; \ + grep -qF 'complete -c ujust' /tmp/ujust-gate/ujust.fish; \ + grep -qx -- '--version' /tmp/ujust-gate/ujust-flags; \ + if grep -qF 'JUST_COMPLETE' /tmp/ujust-gate/ujust /tmp/ujust-gate/_ujust /tmp/ujust-gate/ujust.fish; then echo "ujust completion is a just dynamic-loader shim" >&2; exit 1; fi; \ + for f in usr/share/bash-completion/completions/ujust usr/share/zsh/site-functions/_ujust usr/share/fish/vendor_completions.d/ujust.fish usr/share/ublue-os/just/ujust-flags; do \ + if [ -e "/out/shared/${f}" ]; then echo "ujust completion shadowed by /out/shared/${f}" >&2; exit 1; fi; \ + done + FROM scratch AS ctx COPY /system_files/shared /system_files/shared/ COPY /bluefin-branding/system_files /system_files/bluefin From 057344168412ae0cfc165d2e088e9496721a4d52 Mon Sep 17 00:00:00 2001 From: KiKaraage Date: Wed, 16 Sep 2026 21:47:53 +0700 Subject: [PATCH 4/7] docs: describes new ujust completions in containerfile skill Replace previous ujust completion generation / text-replacement method in build-stages reference with central ujust completions from common https://opncd.ai/share/HiYO5BRh Assisted-by: Muse Spark 1.3 in OpenCode --- docs/skills/containerfile/SKILL.md | 6 +++--- .../containerfile/references/build-stages.md | 16 +++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/skills/containerfile/SKILL.md b/docs/skills/containerfile/SKILL.md index 5eabe7a1..1a7cd379 100644 --- a/docs/skills/containerfile/SKILL.md +++ b/docs/skills/containerfile/SKILL.md @@ -44,7 +44,7 @@ The Containerfile uses four named stages: | `build` | Downloads and assembles all artifacts into `/out/` | | `ctx` | Scratch image: the OCI layer consumed by downstream builds | -See [`references/build-stages.md`](references/build-stages.md) for the full stage details, wallpaper source caveat, and ujust completion generation. +See [`references/build-stages.md`](references/build-stages.md) for the full stage details, wallpaper source caveat, and ujust completions. ## Key Rules @@ -57,7 +57,7 @@ See [`references/build-stages.md`](references/build-stages.md) for the full stag - `checkout tags/...` or `--branch` in a Go builder stage — tags are mutable. - A `curl` block without an inline `sha256sum -c`. -- Editing generated ujust completions directly instead of fixing the `sed` pattern. +- ujust completions are tailored files under `system_files/shared/` guarded by a `RUN` gate in the `build` stage, which never reintroduce a `just --completions | sed` generator. - Using `ghcr.io/projectbluefin/` for the wallpaper source (it is `ublue-os`). ## Verification @@ -71,5 +71,5 @@ See [`references/build-stages.md`](references/build-stages.md) for the full stag | File | Description | |---|---| -| [`references/build-stages.md`](references/build-stages.md) | Full build stage definitions, wallpaper source caveat, and ujust completion generation details. | +| [`references/build-stages.md`](references/build-stages.md) | Full build stage definitions, wallpaper source caveat, and ujust completion details. | | [`references/binary-and-testing.md`](references/binary-and-testing.md) | External binary SHA verification pattern, local testing with `just overlay`, adding a new binary, and Renovate tracking. | diff --git a/docs/skills/containerfile/references/build-stages.md b/docs/skills/containerfile/references/build-stages.md index a8728e00..8d6190a1 100644 --- a/docs/skills/containerfile/references/build-stages.md +++ b/docs/skills/containerfile/references/build-stages.md @@ -1,6 +1,6 @@ # Containerfile — Build Stages -Part of [containerfile](../SKILL.md) — full stage definitions, wallpaper source caveat, and ujust completion generation. +Part of [containerfile](../SKILL.md) — full stage definitions, wallpaper source caveat, and ujust completions. ## Build stages @@ -100,14 +100,12 @@ sed -i 's|~\/\.local\/share|\/usr\/share|' *.xml --- -## ujust completion generation +## ujust completions -The `ujust` shell completions are **not hand-authored** — they are generated at build time from the `just` binary by replacing all occurrences of `just` with `ujust` in the completion output: +The `ujust` shell completions are tailored files checked into `system_files/shared/` (bash, zsh, fish), completing `ujust` flags plus recipe names from `/usr/share/ublue-os/just/00-entry.just` via `just --summary`. +They are **not** generated from `just --completions`: Since `just` moved to dynamic `clap_complete` loader output, a build-time `sed s/just/ujust/` rename can no longer work. The real registration line (`complete ... just`) is emitted at TAB-time on the live system, past any build-time filter, and binds the wrong command name (projectbluefin/bluefin#1171). -```bash -just --completions bash | sed -E 's/([\(_" ])just/\1ujust/g' > .../completions/ujust -just --completions zsh | sed -E 's/([\(_" ])just/\1ujust/g' > .../_ujust -just --completions fish | sed -E 's/([\(_" ])just/\1ujust/g' > .../ujust.fish -``` +Two rules follow from this: -The sed pattern `([\(_" ])just` only substitutes `just` when preceded by `(`, `_`, `"`, ` `, or `(` — avoiding substring matches inside longer words. Do not edit the generated completions directly; edit the sed pattern if the substitution is wrong. +- Never reintroduce a `just --completions | sed` generator step. The gate `RUN` in the `build` stage (content assertions on the checked-in files plus a no-shadow check against `/out/shared/...`) fails the build if the generator — or any other file at those paths — comes back. +- `UJUST_JUSTFILE` / `UJUST_FLAGS_FILE` override the entry-justfile path and the flags list in all three completions; they exist for `tests/test_ujust_completion.bats` which points them at sandbox files so the suite passes off-image. Flags live in exactly one place at `system_files/shared/usr/share/ublue-os/just/ujust-flags` (one per line). All three completions read it during TAB press. From 63e38075e710fc44d74a93ffa7e0c12750b672de Mon Sep 17 00:00:00 2001 From: KiKaraage Date: Wed, 16 Sep 2026 23:01:38 +0700 Subject: [PATCH 5/7] fix: trim whitespace in Containerfile --- Containerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Containerfile b/Containerfile index 0e005d42..ad01eee0 100644 --- a/Containerfile +++ b/Containerfile @@ -78,7 +78,7 @@ RUN set -e && mkdir -p /out/bluefin/etc/bazaar && \ COPY --from=umotd-build /umotd /out/shared/usr/bin/umotd COPY --from=uwelcome-build /uwelcome /out/shared/usr/bin/uwelcome -# Ujust gate: the tailored completions checked into system_files/shared must bind `ujust` +# Ujust gate: the tailored completions checked into system_files/shared must bind `ujust` # & /out/shared must not ship files at the same paths to avoid shadow by ctx overlay. COPY system_files/shared/usr/share/bash-completion/completions/ujust \ system_files/shared/usr/share/zsh/site-functions/_ujust \ From dbfd2e4296f77922dd469f8223a346789739295d Mon Sep 17 00:00:00 2001 From: castrojo <1264109+castrojo@users.noreply.github.com> Date: Fri, 18 Sep 2026 08:21:57 -0400 Subject: [PATCH 6/7] fix: harden ujust completion validation Assisted-by: GPT-5.6 Terra via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/unit-tests.yml | 5 +- Containerfile | 9 ++- .../containerfile/references/build-stages.md | 2 +- tests/test_ujust_completion.bats | 71 ++++++++++++++++--- 4 files changed, 73 insertions(+), 14 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 37a6915b..267b8a01 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -37,7 +37,7 @@ jobs: - name: Install test deps run: | - sudo apt-get install -y bats + sudo apt-get install -y bats fish zsh pip install pytest pytest-cov pyyaml - name: Run shellcheck — extensionless scripts @@ -81,6 +81,9 @@ jobs: - name: Run bats (ublue-bling) run: bats tests/test_bling.bats + - name: Run bats (ujust completion) + run: bats tests/test_ujust_completion.bats + - name: Run bats (bling.sh) run: bats tests/test_bling_sh.bats diff --git a/Containerfile b/Containerfile index ad01eee0..7e8e2457 100644 --- a/Containerfile +++ b/Containerfile @@ -86,9 +86,12 @@ COPY system_files/shared/usr/share/bash-completion/completions/ujust \ system_files/shared/usr/share/ublue-os/just/ujust-flags \ /tmp/ujust-gate/ RUN set -e; \ - grep -qF 'complete -F _ujust ujust' /tmp/ujust-gate/ujust; \ - grep -qF '#compdef ujust' /tmp/ujust-gate/_ujust; \ - grep -qF 'complete -c ujust' /tmp/ujust-gate/ujust.fish; \ + grep -qE '^complete -F _ujust ujust$' /tmp/ujust-gate/ujust; \ + grep -qE '^#compdef ujust$' /tmp/ujust-gate/_ujust; \ + grep -qE '^complete -c ujust ' /tmp/ujust-gate/ujust.fish; \ + grep -qE '^[[:space:]]*local flags_file=.*ujust-flags' /tmp/ujust-gate/ujust; \ + grep -qE '^[[:space:]]*local flags_file=.*ujust-flags' /tmp/ujust-gate/_ujust; \ + grep -qE '^[[:space:]]*echo .*ujust-flags' /tmp/ujust-gate/ujust.fish; \ grep -qx -- '--version' /tmp/ujust-gate/ujust-flags; \ if grep -qF 'JUST_COMPLETE' /tmp/ujust-gate/ujust /tmp/ujust-gate/_ujust /tmp/ujust-gate/ujust.fish; then echo "ujust completion is a just dynamic-loader shim" >&2; exit 1; fi; \ for f in usr/share/bash-completion/completions/ujust usr/share/zsh/site-functions/_ujust usr/share/fish/vendor_completions.d/ujust.fish usr/share/ublue-os/just/ujust-flags; do \ diff --git a/docs/skills/containerfile/references/build-stages.md b/docs/skills/containerfile/references/build-stages.md index 8d6190a1..d15357d8 100644 --- a/docs/skills/containerfile/references/build-stages.md +++ b/docs/skills/containerfile/references/build-stages.md @@ -107,5 +107,5 @@ They are **not** generated from `just --completions`: Since `just` moved to dyna Two rules follow from this: -- Never reintroduce a `just --completions | sed` generator step. The gate `RUN` in the `build` stage (content assertions on the checked-in files plus a no-shadow check against `/out/shared/...`) fails the build if the generator — or any other file at those paths — comes back. +- Never reintroduce a `just --completions | sed` generator step. The gate `RUN` in the `build` stage validates uncommented completion registrations and `ujust-flags` path assignments in the checked-in files, plus a no-shadow check against `/out/shared/...`. It fails if the generator — or any other file at those paths — comes back. - `UJUST_JUSTFILE` / `UJUST_FLAGS_FILE` override the entry-justfile path and the flags list in all three completions; they exist for `tests/test_ujust_completion.bats` which points them at sandbox files so the suite passes off-image. Flags live in exactly one place at `system_files/shared/usr/share/ublue-os/just/ujust-flags` (one per line). All three completions read it during TAB press. diff --git a/tests/test_ujust_completion.bats b/tests/test_ujust_completion.bats index 33cb5991..724a0b38 100644 --- a/tests/test_ujust_completion.bats +++ b/tests/test_ujust_completion.bats @@ -51,7 +51,7 @@ teardown() { @test "bash completion file binds the ujust command" { [ -f "${BASH_COMPLETION}" ] - grep -qF "complete -F _ujust ujust" "${BASH_COMPLETION}" + grep -qE '^complete -F _ujust ujust$' "${BASH_COMPLETION}" grep -qF "just --summary" "${BASH_COMPLETION}" grep -qF "UJUST_JUSTFILE" "${BASH_COMPLETION}" } @@ -64,7 +64,7 @@ teardown() { @test "zsh completion file defines a ujust completer" { [ -f "${ZSH_COMPLETION}" ] - grep -qF "#compdef ujust" "${ZSH_COMPLETION}" + grep -qE '^#compdef ujust$' "${ZSH_COMPLETION}" grep -qF "_ujust()" "${ZSH_COMPLETION}" grep -qF "just --summary" "${ZSH_COMPLETION}" grep -qF "UJUST_JUSTFILE" "${ZSH_COMPLETION}" @@ -84,7 +84,7 @@ teardown() { @test "fish completion file completes the ujust command" { [ -f "${FISH_COMPLETION}" ] - grep -qF "complete -c ujust" "${FISH_COMPLETION}" + grep -qE '^complete -c ujust ' "${FISH_COMPLETION}" grep -qF "just --summary" "${FISH_COMPLETION}" grep -qF "UJUST_JUSTFILE" "${FISH_COMPLETION}" } @@ -96,9 +96,9 @@ teardown() { } @test "completions default to the image entry justfile" { - grep -qF "${ENTRY_JUSTFILE}" "${BASH_COMPLETION}" - grep -qF "${ENTRY_JUSTFILE}" "${ZSH_COMPLETION}" - grep -qF "${ENTRY_JUSTFILE}" "${FISH_COMPLETION}" + grep -qE '^[[:space:]]*local justfile=.*00-entry\.just' "${BASH_COMPLETION}" + grep -qE '^[[:space:]]*local justfile=.*00-entry\.just' "${ZSH_COMPLETION}" + grep -qE "^[[:space:]]*echo ${ENTRY_JUSTFILE}$" "${FISH_COMPLETION}" } @test "fish completion file is not a just dynamic-loader shim" { @@ -120,12 +120,21 @@ teardown() { } @test "completions read flags from the data file instead of embedding lists" { - grep -qF "ujust-flags" "${BASH_COMPLETION}" - grep -qF "ujust-flags" "${ZSH_COMPLETION}" - grep -qF "ujust-flags" "${FISH_COMPLETION}" + grep -qE '^[[:space:]]*local flags_file=.*ujust-flags' "${BASH_COMPLETION}" + grep -qE '^[[:space:]]*local flags_file=.*ujust-flags' "${ZSH_COMPLETION}" + grep -qE '^[[:space:]]*echo .*ujust-flags' "${FISH_COMPLETION}" ! grep -qF -- "--list-heading" "${BASH_COMPLETION}" "${ZSH_COMPLETION}" "${FISH_COMPLETION}" } +@test "Containerfile gate validates executable completion configuration" { + grep -qF "grep -qE '^complete -F _ujust ujust$'" "$REPO_ROOT/Containerfile" + grep -qF "grep -qE '^#compdef ujust$'" "$REPO_ROOT/Containerfile" + grep -qF "grep -qE '^complete -c ujust '" "$REPO_ROOT/Containerfile" + grep -qF "grep -qE '^[[:space:]]*local flags_file=.*ujust-flags' /tmp/ujust-gate/ujust;" "$REPO_ROOT/Containerfile" + grep -qF "grep -qE '^[[:space:]]*local flags_file=.*ujust-flags' /tmp/ujust-gate/_ujust;" "$REPO_ROOT/Containerfile" + grep -qF "grep -qE '^[[:space:]]*echo .*ujust-flags'" "$REPO_ROOT/Containerfile" +} + # --------------------------------------------------------------------------- # Functional tests: completions offer recipes from the entry justfile. # --------------------------------------------------------------------------- @@ -185,6 +194,23 @@ teardown() { [[ "${output}" == *--list* ]] } +@test "bash completion finds flags next to the entry justfile by default" { + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" BASH_COMPLETION="${BASH_COMPLETION}" \ + bash -c ' + source "${BASH_COMPLETION}" + COMP_WORDS=(ujust --l) + COMP_CWORD=1 + COMP_LINE="ujust --l" + COMP_POINT=9 + COMPREPLY=() + _ujust ujust --l "" + printf "%s\n" "${COMPREPLY[@]}" + ' + + [ "${status}" -eq 0 ] + [[ "${output}" == *--list* ]] +} + @test "bash completion offers -V (version), distinct from -v (verbose)" { run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" UJUST_FLAGS_FILE="${WORKDIR}/ujust-flags" BASH_COMPLETION="${BASH_COMPLETION}" \ bash -c ' @@ -290,6 +316,23 @@ teardown() { [ "$(grep -cw "update" "${out}" || true)" -eq 0 ] } +@test "zsh completion finds flags next to the entry justfile by default" { + [ -n "$(command -v zsh)" ] || skip "zsh not installed" + local out="${WORKDIR}/zsh-flags-default.txt" + + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" OUT="${out}" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" ZSH_COMPLETION="${ZSH_COMPLETION}" \ + zsh -c ' + _call_program() { local _tag=$1; shift; "$@" } + _describe() { print -r -- "${(P)${@[-1]}}" > "$OUT" } + CURRENT=2 + words=(ujust --l) + source "${ZSH_COMPLETION}" + ' + + [ "${status}" -eq 0 ] + grep -qw -- "--list" "${out}" +} + @test "zsh completion falls back to recipes when the flags file is missing" { [ -n "$(command -v zsh)" ] || skip "zsh not installed" local out="${WORKDIR}/zsh-flags-missing.txt" @@ -341,6 +384,16 @@ teardown() { [[ "${output}" == *--list* ]] } +@test "fish completion finds flags next to the entry justfile by default" { + [ -n "$(command -v fish)" ] || skip "fish not installed" + + run env PATH="${WORKDIR}/bin:/usr/bin:/bin" UJUST_JUSTFILE="${WORKDIR}/00-entry.just" FISH_COMPLETION="${FISH_COMPLETION}" \ + fish --private -c 'set -g fish_complete_path; source "$FISH_COMPLETION"; complete -C"ujust --l"' + + [ "${status}" -eq 0 ] + [[ "${output}" == *--list* ]] +} + @test "fish completion offers -V (version)" { [ -n "$(command -v fish)" ] || skip "fish not installed" From 055a887167c58da352a300bcdb9d7a3b2a01a33d Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Sat, 19 Sep 2026 15:42:59 -0400 Subject: [PATCH 7/7] fix(bling): complete ujust flag list and clarify red flag - ujust-flags now mirrors every flag just 1.58.0 accepts (ujust execs just with "${@}"), adding --alias-style, --allow-missing, --ceiling, --chooser, --cygpath, --default-list, --dotenv-command, --dotenv-filename, --dotenv-path, --group, --indentation, --json, --justfile-name, --no-cache, --tempdir, --time, --timestamp-format, and dropping --format, which just does not accept. - Reword the containerfile SKILL.md Red Flags bullet so it names the anti-pattern instead of restating the correct design. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/skills/containerfile/SKILL.md | 2 +- .../shared/usr/share/ublue-os/just/ujust-flags | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/skills/containerfile/SKILL.md b/docs/skills/containerfile/SKILL.md index 1a7cd379..a15a1b26 100644 --- a/docs/skills/containerfile/SKILL.md +++ b/docs/skills/containerfile/SKILL.md @@ -57,7 +57,7 @@ See [`references/build-stages.md`](references/build-stages.md) for the full stag - `checkout tags/...` or `--branch` in a Go builder stage — tags are mutable. - A `curl` block without an inline `sha256sum -c`. -- ujust completions are tailored files under `system_files/shared/` guarded by a `RUN` gate in the `build` stage, which never reintroduce a `just --completions | sed` generator. +- Reintroducing a `just --completions | sed` generator for ujust completions, or shipping files at the ujust completion paths from `/out/shared/`, instead of editing the checked-in files under `system_files/shared/` — the `build` stage `RUN` gate fails the build. - Using `ghcr.io/projectbluefin/` for the wallpaper source (it is `ublue-os`). ## Verification diff --git a/system_files/shared/usr/share/ublue-os/just/ujust-flags b/system_files/shared/usr/share/ublue-os/just/ujust-flags index 602916af..aa4d8d45 100644 --- a/system_files/shared/usr/share/ublue-os/just/ujust-flags +++ b/system_files/shared/usr/share/ublue-os/just/ujust-flags @@ -1,6 +1,10 @@ +--alias-style +--allow-missing +--ceiling --changelog --check --choose +--chooser --clean --clear-shell-args --color @@ -8,6 +12,11 @@ --command-color --complete-aliases --completions +--cygpath +--default-list +--dotenv-command +--dotenv-filename +--dotenv-path --dry-run --dump --dump-format @@ -16,20 +25,24 @@ --evaluate-format --explain --fmt ---format --global-justfile +--group --groups --help --highlight +--indentation --init --jobs +--json --justfile +--justfile-name --list --list-heading --list-prefix --list-submodules --man --no-aliases +--no-cache --no-deps --no-dotenv --no-highlight @@ -41,7 +54,10 @@ --shell-command --show --summary +--tempdir +--time --timestamp +--timestamp-format --unsorted --unstable --usage