settings: three tiers - wikitool.json (instance), .wikitool-local.json (checkout), secrets by reference incl. 1Password CLI; new command config set (#207)
CI / verify (push) Successful in 8m5s
CI / pwsh (push) Successful in 2m34s
Release / release (push) Successful in 36s
Release / wiki-mirror (push) Skipped

Every settings field declares its tier; a value in the wrong file is an error naming
file, key and tier. A field naming a program or affecting a gate cannot be declared
instance. Secrets are references only: {"ref": "<name>"} via WIKITOOL_SECRET_<NAME> or
a user-only secrets file, {"ref": "op://..."} via op read (locked 1Password: exit 42).
The preflight records op as an optional tool. doctor gains one line per tier, docs
verify checks a committed wikitool.json for plaintext secrets, CI resolves a real
op:// value through 1password/load-secrets-action. No feature reads its settings
this way yet; without the two files every other command is unchanged.

Files changed:
- .gitea/workflows/ci.yml
- .gitignore
- AGENTS.md
- CHANGES.md
- INSTALL.md
- VERSION
- docs/explanation/README.md
- docs/explanation/configuration-tiers.md
- docs/how-to/README.md
- docs/how-to/use-1password-for-settings.md
- docs/reference/commands/README.md
- docs/reference/commands/configuration.md
- docs/reference/commands/instance-health.md
- docs/reference/commands/types-instructions-and-docs.md
- docs/reference/configuration.md
- docs/reference/exit-codes.md
- instructions/dev/doc-pull-through.md
- instructions/dev/testing-conventions.md
- instructions/preflight.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli.py
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/_util.py
- tools/chemenu/commands/config_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/config.py
- tools/chemenu/config_shapes.py
- tools/chemenu/prerequisites.py
- tools/chemenu/settings.py
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_dist_cmd.py
- tools/chemenu/tests/test_preflight.py
- tools/chemenu/tests/test_preflight_pwsh.py
- tools/chemenu/tests/test_settings.py
- tools/chemenu/toolpaths.py
- tools/preflight.ps1
- tools/preflight.sh
- tools/prerequisites.txt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
torbenandClaude Opus 5.5 committed 2026-10-10 15:34:28 +02:00
1 parent 059a0a1840
commit f6aaadc413
40 files changed
+2246 -31

No files matched your search

+46 -3
View File
@@ -456,6 +456,14 @@ while IFS='|' read -r kind name minimum platforms rest; do
fi
done < "$MANIFEST"
# Recorded when found, never asked for - see the manifest's own header.
OPTIONAL=""
while IFS='|' read -r kind name rest; do
[ "$kind" = optional ] || continue
case "$name" in *[!a-z0-9]*|'') echo "preflight: bad tool name '$name' in $MANIFEST" >&2; exit 1 ;; esac
OPTIONAL="$OPTIONAL $name"
done < "$MANIFEST"
# The install command for this machine's package manager, or every known one.
install_hint() { # <tool>
choco=$(manifest_field tool "$1" 7)
@@ -561,9 +569,9 @@ set_value() { # <name> -> the path given with --set, if any
# --- --set: every named path has to work, or nothing is written -------------------
for entry in $(printf '%s\n' "$SETS" | sed -n 's/^\([^=]*\)=.*/\1/p'); do
case " $TOOLS " in
case " $TOOLS $OPTIONAL " in
*" $entry "*) ;;
*) echo "preflight: --set names '$entry', which is not a tool this platform needs:$TOOLS" >&2
*) echo "preflight: --set names '$entry', which is not a tool this platform needs:$TOOLS (optional:$OPTIONAL)" >&2
exit 1 ;;
esac
done
@@ -705,6 +713,41 @@ $SELF --set $tool=<full path to $tool>"
eval "FOUND_$tool=\$native"
done
# --- optional tools: recorded when found, never a problem when not ---------------
for tool in $OPTIONAL; do
label=$(manifest_field optional "$tool" 3)
given=$(set_value "$tool")
path=""
if [ -n "$given" ]; then
if usable "$given"; then
path=$given
else
problem "The path given for $label does not work: $given" \
"$(manifest_field optional "$tool" 4)" \
"Check the path - it has to be the $tool executable itself.
Then run: $SELF --set $tool=<full path to $tool>"
BAD_SET=1
continue
fi
else
previous=$(recorded "$tool") || previous=""
if [ -n "$previous" ] && usable "$previous"; then
path=$previous
else
path=$(on_path "$tool" | head -n 1)
fi
fi
if [ -z "$path" ]; then
report ABSENT "$tool" - "optional, not installed"
continue
fi
version=$(version_of "$("$path" --version 2>/dev/null | tr -d '\r')")
native=$(native_path "$path")
report OK "$tool" "${version:--}" "$native"
eval "FOUND_$tool=\$native"
done
# --- install folder length (Windows, long paths off) ------------------------------
if [ "$PLATFORM" = windows ] && ! longpaths_enabled; then
@@ -730,7 +773,7 @@ write_tools_file() { # <true|false>
{
printf '{\n "schema": 1,\n "complete": %s,\n "tools": {' "$1"
separator=""
for tool in $TOOLS; do
for tool in $TOOLS $OPTIONAL; do
eval "value=\${FOUND_$tool:-}"
[ -n "$value" ] || continue
printf '%s\n "%s": "%s"' "$separator" "$tool" "$(json_string "$value")"