← Files Compound EngineeringARCHIVED FILE
skills/ce-setup/scripts/check-health
27.8 KB · Oct 5, 2026 · 18:34 UTC
#!/usr/bin/env bash
# Compound Engineering environment health check.
# Reports optional tool capabilities and repo-local config safety in one pass.
set -o pipefail
# =====================================================
# Optional capability config
# =====================================================
# Format: name|install_cmd|url|capability
deps=(
"agent-browser|CI=true npm install -g agent-browser --no-audit --no-fund --loglevel=error && agent-browser install|https://github.com/vercel-labs/agent-browser|browser testing and dogfood QA"
"gh|NONINTERACTIVE=1 HOMEBREW_NO_AUTO_UPDATE=1 brew install -q gh|https://cli.github.com|GitHub PR, issue, and review workflows"
"jq|NONINTERACTIVE=1 HOMEBREW_NO_AUTO_UPDATE=1 brew install -q jq|https://jqlang.github.io/jq/|JSON inspection in shell-based workflows"
"ast-grep|NONINTERACTIVE=1 HOMEBREW_NO_AUTO_UPDATE=1 brew install -q ast-grep|https://ast-grep.github.io|syntax-aware structural code search"
"ffmpeg|NONINTERACTIVE=1 HOMEBREW_NO_AUTO_UPDATE=1 brew install -q ffmpeg|https://ffmpeg.org/download.html|media chunking and screenshot extraction for Riffrec analysis"
)
# =====================================================
# Args
# =====================================================
plugin_version=""
while [ $# -gt 0 ]; do
case "$1" in
--version) [ -n "$2" ] && plugin_version="$2" && shift 2 || shift ;;
*) shift ;;
esac
done
# =====================================================
# Helpers
# =====================================================
ok() { echo " 🟢 $1"; }
warn() { echo " 🟡 $1"; }
skip() { echo " ➖ $1"; }
detail() { echo " $1"; }
section() { echo ""; echo " $1"; }
# Read one top-level scalar from the repo's flat local-config convention. This is
# intentionally not a general YAML parser: comments and absent/empty keys are
# ignored, surrounding quotes are removed, and values are never evaluated.
read_flat_config_value() {
local config_file="$1"
local config_key="$2"
local value
value=$(awk -v key="$config_key" '
$0 ~ "^" key "[[:space:]]*:" {
sub("^" key "[[:space:]]*:[[:space:]]*", "")
sub(/[[:space:]]+#.*$/, "")
sub(/^[[:space:]]+/, "")
sub(/[[:space:]]+$/, "")
print
exit
}
' "$config_file")
case "$value" in
\"*\") value=${value#\"}; value=${value%\"} ;;
\'*\') value=${value#\'}; value=${value%\'} ;;
esac
printf '%s' "$value"
}
# Resolve the symlink-followed absolute path of $1 without relying on `realpath -m`
# (absent on stock macOS/BSD). Resolves the existing prefix with `cd`/`pwd -P`,
# then re-appends any not-yet-created tail — enough to catch a symlink in the
# existing portion escaping the repository, which is the only way a relative
# value can escape.
resolve_real_best_effort() {
local target="$1" tail="" existing base
existing="$target"
while [ ! -e "$existing" ] && [ "$existing" != "/" ] && [ "$existing" != "." ] && [ "$existing" != "$(dirname "$existing")" ]; do
tail="/$(basename "$existing")$tail"
existing="$(dirname "$existing")"
done
if [ -d "$existing" ]; then
base="$(cd "$existing" 2>/dev/null && pwd -P)" || return 1
elif [ -e "$existing" ]; then
base="$(cd "$(dirname "$existing")" 2>/dev/null && pwd -P)/$(basename "$existing")" || return 1
else
return 1
fi
printf '%s' "${base}${tail}"
}
# Resolve docs_root from tracked config.yaml only. A docs_root in
# config.local.yaml is ignored. Unset -> default root `docs`. A configured
# value is validated and rejected (never silently defaulted) when it is
# absolute, escapes the repository via path or symlink, resolves to the repo
# root or inside .git/, or names an existing non-directory. Sets
# docs_root_status (default|configured|invalid), docs_root_value,
# docs_root_source, docs_root_error, and docs_root_local_ignored.
resolve_docs_root() {
local repo_root="$1"
local local_cfg="$repo_root/.compound-engineering/config.local.yaml"
local tracked_cfg="$repo_root/.compound-engineering/config.yaml"
local value="" source="" repo_real real local_docs probe
docs_root_error=""
docs_root_local_ignored=""
if [ -f "$local_cfg" ]; then
local_docs=$(read_flat_config_value "$local_cfg" "docs_root")
[ -n "$local_docs" ] && docs_root_local_ignored="$local_docs"
fi
if [ -f "$tracked_cfg" ]; then
value=$(read_flat_config_value "$tracked_cfg" "docs_root")
[ -n "$value" ] && source="config.yaml"
fi
if [ -z "$value" ]; then
docs_root_status="default"; docs_root_value="docs"; docs_root_source="default"; return
fi
docs_root_value="$value"; docs_root_source="$source"; docs_root_status="invalid"
case "$value" in
/*) docs_root_error="absolute paths are not allowed; use a repo-relative path"; return ;;
esac
# Reject any `..` path component up front. resolve_real_best_effort only
# collapses `..` within the existing prefix (via cd/pwd -P); a `..` that
# traverses a not-yet-created segment would otherwise survive literally and
# escape the repo, hit the repo root, or reach .git/ while still string-prefix
# matching. A legitimate repo-relative artifact root never needs `..`.
case "/$value/" in
*/../*) docs_root_error="path traversal ('..') is not allowed; use a plain repo-relative path"; return ;;
esac
repo_real="$(cd "$repo_root" 2>/dev/null && pwd -P)" || { docs_root_error="could not resolve the repository root"; return; }
real="$(resolve_real_best_effort "$repo_root/$value")" || { docs_root_error="could not resolve the path"; return; }
case "$real/" in
"$repo_real/"*) ;;
*) docs_root_error="resolves outside the repository ($real)"; return ;;
esac
[ "$real" = "$repo_real" ] && { docs_root_error="resolves to the repository root itself"; return; }
case "$real/" in
"$repo_real/.git/"*) docs_root_error="resolves inside .git/"; return ;;
esac
if [ -e "$real" ] && [ ! -d "$real" ]; then
docs_root_error="names an existing non-directory"; return
fi
# Reject when an intermediate component is an existing non-directory (e.g.
# `afile/nested` where `afile` is a file): the leaf-only check above passes
# because `$real` itself does not exist, but `mkdir -p` would fail. Walk up to
# the deepest existing ancestor and require it be a directory.
probe="$real"
while [ ! -e "$probe" ] && [ "$probe" != "/" ] && [ "$probe" != "$(dirname "$probe")" ]; do
probe="$(dirname "$probe")"
done
if [ -e "$probe" ] && [ ! -d "$probe" ]; then
docs_root_error="an intermediate path component is not a directory"; return
fi
docs_root_status="configured"
}
# Report whether a retired top-level key is still present without interpreting
# its value. Detection is intentionally separate from routing so legacy scalar
# settings can receive a migration diagnostic without remaining supported.
has_flat_config_key() {
local config_file="$1"
local config_key="$2"
awk -v key="$config_key" '
$0 ~ "^" key "[[:space:]]*:" { found = 1 }
END { exit(found ? 0 : 1) }
' "$config_file"
}
# First non-empty ordinary scalar across local then tracked. Empty/commented
# local continues to tracked. Sets ordinary_value and ordinary_source.
resolve_ordinary_scalar() {
local local_file="$1"
local tracked_file="$2"
local config_key="$3"
local value=""
ordinary_value=""
ordinary_source=""
if [ -f "$local_file" ]; then
value=$(read_flat_config_value "$local_file" "$config_key")
if [ -n "$value" ]; then
ordinary_value="$value"
ordinary_source="config.local.yaml"
return
fi
fi
if [ -f "$tracked_file" ]; then
value=$(read_flat_config_value "$tracked_file" "$config_key")
if [ -n "$value" ]; then
ordinary_value="$value"
ordinary_source="config.yaml"
fi
fi
}
# Present list/map key (including `[]`) wins that layer. Sets
# structured_file, or empty when neither layer sets the key.
resolve_structured_layer() {
local local_file="$1"
local tracked_file="$2"
local config_key="$3"
structured_file=""
if [ -f "$local_file" ] && has_flat_config_key "$local_file" "$config_key"; then
structured_file="$local_file"
return
fi
if [ -f "$tracked_file" ] && has_flat_config_key "$tracked_file" "$config_key"; then
structured_file="$tracked_file"
fi
}
# Read the narrow YAML sequence used by work_engine_preferences. The local
# config remains human-authored YAML, but setup health needs only this one
# deterministic shape rather than a general parser.
read_work_engine_preferences() {
local config_file="$1"
awk '
function trim(value) {
sub(/^[[:space:]]+/, "", value)
sub(/[[:space:]]+$/, "", value)
return value
}
function scalar(value) {
sub(/[[:space:]]+#.*$/, "", value)
value = trim(value)
if (value ~ /^".*"$/ || value ~ /^\047.*\047$/) {
value = substr(value, 2, length(value) - 2)
}
return value
}
function emit_item() {
if (!have_item) return
if (harness == "" && model != "") {
print "ERROR\tmodel \047" model "\047 has no harness in work_engine_preferences"
} else if (harness == "") {
print "ERROR\tempty item in work_engine_preferences"
} else {
print "ITEM\t" harness "\t" (model == "" ? "default" : model)
}
have_item = 0
harness = ""
model = ""
}
/^[^[:space:]#-][^:]*[[:space:]]*:/ {
if (active) {
emit_item()
active = 0
}
}
/^work_engine_preferences[[:space:]]*:/ {
active = 1
next
}
active {
line = $0
if (line ~ /^[[:space:]]*($|#)/) next
if (line ~ /^[[:space:]]*-[[:space:]]*harness[[:space:]]*:/) {
emit_item()
sub(/^[[:space:]]*-[[:space:]]*harness[[:space:]]*:[[:space:]]*/, "", line)
harness = scalar(line)
have_item = 1
next
}
if (line ~ /^[[:space:]]*-[[:space:]]*model[[:space:]]*:/) {
emit_item()
sub(/^[[:space:]]*-[[:space:]]*model[[:space:]]*:[[:space:]]*/, "", line)
model = scalar(line)
have_item = 1
next
}
if (line ~ /^[[:space:]]+model[[:space:]]*:/) {
sub(/^[[:space:]]+model[[:space:]]*:[[:space:]]*/, "", line)
model = scalar(line)
if (!have_item) have_item = 1
next
}
if (line ~ /^[[:space:]]+harness[[:space:]]*:/) {
sub(/^[[:space:]]+harness[[:space:]]*:[[:space:]]*/, "", line)
harness = scalar(line)
if (!have_item) have_item = 1
next
}
print "ERROR\tunsupported work_engine_preferences entry: " trim(line)
}
END {
if (active) emit_item()
}
' "$config_file"
}
has_brew=$(command -v brew >/dev/null 2>&1 && echo "yes" || echo "no")
in_repo=$(git rev-parse --is-inside-work-tree >/dev/null 2>&1 && echo "yes" || echo "no")
# Retired Bun-era Codex tool map (#1099). The block is present only when a
# standalone BEGIN line is followed by a standalone END line.
has_codex_tool_map() {
awk '
{ sub(/\r$/, "") }
$0 == "<!-- BEGIN COMPOUND CODEX TOOL MAP -->" { seen = 1 }
seen && $0 == "<!-- END COMPOUND CODEX TOOL MAP -->" { found = 1; exit }
END { exit found ? 0 : 1 }
' "$1"
}
codex_agents_file="${CODEX_HOME:-$HOME/.codex}/AGENTS.md"
legacy_codex_map="no"
if [ -f "$codex_agents_file" ] && has_codex_tool_map "$codex_agents_file"; then
legacy_codex_map="yes"
fi
# =====================================================
# Check optional capabilities
# =====================================================
capability_ok=0
capability_total=0
capability_missing=0
results=()
for entry in "${deps[@]}"; do
IFS='|' read -r name install_cmd url capability < <(printf '%s\n' "$entry")
capability_total=$((capability_total + 1))
if command -v "$name" >/dev/null 2>&1; then
capability_ok=$((capability_ok + 1))
results+=("$name|ok|$install_cmd|$url|$capability")
else
capability_missing=$((capability_missing + 1))
results+=("$name|missing|$install_cmd|$url|$capability")
fi
done
# =====================================================
# Project checks (repo only)
# =====================================================
legacy_cfg="skip"
repo_cfg_gitignore="skip"
scratch_gitignore="skip"
local_cfg="skip"
example_cfg="skip"
retired_keys=()
work_engine_cfg="skip"
work_engine_detail=""
work_engine_preferences_note=""
work_engine_preferences_note_level="detail"
work_engine_migration_note=""
docs_root_status="skip"
docs_root_value=""
docs_root_source=""
docs_root_error=""
docs_root_local_ignored=""
tracked_cfg="skip"
project_issues=0
if [ "$in_repo" = "yes" ]; then
repo_root=$(git rev-parse --show-toplevel 2>/dev/null)
local_config_path="$repo_root/.compound-engineering/config.local.yaml"
tracked_config_path="$repo_root/.compound-engineering/config.yaml"
resolve_docs_root "$repo_root"
[ "$docs_root_status" = "invalid" ] && project_issues=$((project_issues + 1))
legacy_cfg="missing"
[ -f "$repo_root/compound-engineering.local.md" ] && legacy_cfg="present"
local_cfg="missing"
if [ -e "$local_config_path" ]; then
local_cfg="present"
if git check-ignore -q "$local_config_path" 2>/dev/null; then
repo_cfg_gitignore="ok"
else
repo_cfg_gitignore="missing"
fi
fi
# Trailing slash is load-bearing: without it an existing directory-only rule
# is missed before the directory exists, and a configured repo reads as bare.
scratch_gitignore="missing"
if git -C "$repo_root" check-ignore -q .context/compound-engineering/ 2>/dev/null; then
scratch_gitignore="ok"
fi
tracked_cfg="missing"
[ -f "$tracked_config_path" ] && tracked_cfg="present"
resolve_ordinary_scalar "$local_config_path" "$tracked_config_path" "work_engine_mode"
work_engine_mode="$ordinary_value"
case "$work_engine_mode" in
""|off|prefer|require) ;;
*)
if [ "$ordinary_source" = "config.local.yaml" ]; then
if [ -f "$tracked_config_path" ]; then
work_engine_mode=$(read_flat_config_value "$tracked_config_path" "work_engine_mode")
else
work_engine_mode=""
fi
fi
;;
esac
resolve_structured_layer "$local_config_path" "$tracked_config_path" "work_engine_preferences"
work_engine_preferences_count=0
work_engine_preferences_detail=""
work_engine_preferences_error=""
retired_work_engine_keys=""
for retired_key in work_engine_target work_engine_model; do
if { [ -f "$local_config_path" ] && has_flat_config_key "$local_config_path" "$retired_key"; } || \
{ [ -f "$tracked_config_path" ] && has_flat_config_key "$tracked_config_path" "$retired_key"; }; then
if [ -n "$retired_work_engine_keys" ]; then
retired_work_engine_keys="${retired_work_engine_keys}, ${retired_key}"
else
retired_work_engine_keys="$retired_key"
fi
fi
done
if [ -n "$retired_work_engine_keys" ]; then
work_engine_migration_note="retired config key(s) ${retired_work_engine_keys} detected; migrate routing to work_engine_preferences entries with harness and optional model fields, then remove the retired keys"
project_issues=$((project_issues + 1))
fi
if [ -n "$structured_file" ]; then
while IFS=$'\t' read -r preference_kind preference_harness preference_model; do
case "$preference_kind" in
ITEM)
work_engine_preferences_count=$((work_engine_preferences_count + 1))
case "$preference_harness" in
codex|claude|grok|cursor|opencode) ;;
*)
[ -z "$work_engine_preferences_error" ] && work_engine_preferences_error="invalid harness '$preference_harness' in work_engine_preferences"
;;
esac
if [ "$preference_model" != "default" ]; then
case "$preference_model" in
[A-Za-z0-9]*)
case "$preference_model" in
*[!A-Za-z0-9._:/-]*)
[ -z "$work_engine_preferences_error" ] && work_engine_preferences_error="invalid model '$preference_model' in work_engine_preferences"
;;
esac
;;
*)
[ -z "$work_engine_preferences_error" ] && work_engine_preferences_error="invalid model '$preference_model' in work_engine_preferences"
;;
esac
fi
preference_display="${preference_harness}@${preference_model}"
if [ -n "$work_engine_preferences_detail" ]; then
work_engine_preferences_detail="${work_engine_preferences_detail}, ${preference_display}"
else
work_engine_preferences_detail="$preference_display"
fi
;;
ERROR)
[ -z "$work_engine_preferences_error" ] && work_engine_preferences_error="$preference_harness"
;;
esac
done < <(read_work_engine_preferences "$structured_file")
fi
case "$work_engine_mode" in
""|off)
work_engine_cfg="native"
if [ -n "$work_engine_mode" ]; then
work_engine_detail="standing preference is off"
else
work_engine_detail="setting is commented or missing"
fi
if [ -n "$work_engine_preferences_error" ]; then
work_engine_preferences_note="invalid dormant work_engine_preferences: ${work_engine_preferences_error}"
work_engine_preferences_note_level="warn"
project_issues=$((project_issues + 1))
elif [ "$work_engine_preferences_count" -gt 0 ]; then
work_engine_preferences_note="ordered preferences ignored while standing mode is off"
fi
;;
prefer|require)
if [ -n "$work_engine_preferences_error" ]; then
work_engine_cfg="unavailable"
work_engine_detail="$work_engine_preferences_error"
project_issues=$((project_issues + 1))
elif [ "$work_engine_preferences_count" -eq 0 ] && [ -n "$retired_work_engine_keys" ]; then
work_engine_cfg="unavailable"
work_engine_detail="$work_engine_mode cannot use retired scalar routing; migrate ${retired_work_engine_keys} to work_engine_preferences"
elif [ "$work_engine_preferences_count" -eq 0 ]; then
work_engine_cfg="unavailable"
work_engine_detail="$work_engine_mode requires work_engine_preferences"
project_issues=$((project_issues + 1))
else
work_engine_cfg="$work_engine_mode"
work_engine_detail="$work_engine_preferences_detail"
fi
;;
*)
work_engine_cfg="invalid"
work_engine_detail="invalid mode '$work_engine_mode' ignored; native is the default"
project_issues=$((project_issues + 1))
;;
esac
script_dir="$(cd "$(dirname "$0")" && pwd)"
template="$script_dir/../references/config-template.yaml"
example="$repo_root/.compound-engineering/config.example.yaml"
if [ ! -f "$example" ]; then
example_cfg="missing"
elif [ -f "$template" ] && ! diff -q "$template" "$example" >/dev/null 2>&1; then
example_cfg="outdated"
else
example_cfg="ok"
fi
# Retired keys set as ACTIVE (non-commented) in either layer. A
# commented `# plan_use_fable:` line does not match `^[[:space:]]*<key>:`.
for cfg_file in "$local_config_path" "$tracked_config_path"; do
[ -f "$cfg_file" ] || continue
for key in plan_use_fable brainstorm_use_fable fable_nudge; do
if grep -Eq "^[[:space:]]*${key}[[:space:]]*:" "$cfg_file" 2>/dev/null; then
already=""
for seen in "${retired_keys[@]}"; do
[ "$seen" = "$key" ] && already=1
done
[ -z "$already" ] && retired_keys+=("$key")
fi
done
done
fi
# =====================================================
# Output
# =====================================================
echo ""
if [ -n "$plugin_version" ]; then
ok "Plugin version v${plugin_version}"
fi
section "Optional capabilities ${capability_ok}/${capability_total}"
for result in "${results[@]}"; do
IFS='|' read -r name status install_cmd url capability < <(printf '%s\n' "$result")
if [ "$status" = "ok" ]; then
ok "$name -- $capability"
else
warn "$name -- unavailable: $capability"
if [[ "$install_cmd" == *"brew install"* ]] && [ "$has_brew" != "yes" ]; then
detail "$url"
else
detail "$install_cmd"
detail "$url"
fi
fi
done
if [ "$legacy_codex_map" = "yes" ]; then
section "Codex instructions"
warn "Legacy Compound Codex tool map in ${codex_agents_file}"
detail "Retired block from a pre-native Bun install; one line tells Codex to collapse subagent dispatch."
detail "Remove it -- see this skill's references/legacy-codex-tool-map.md"
fi
if [ "$in_repo" = "yes" ]; then
section "Project config"
if [ "$legacy_cfg" = "present" ]; then
warn "Obsolete compound-engineering.local.md exists"
project_issues=$((project_issues + 1))
else
ok "No obsolete compound-engineering.local.md"
fi
if [ "$tracked_cfg" = "present" ]; then
ok ".compound-engineering/config.yaml exists"
else
skip "No repo config yet (.compound-engineering/config.yaml)"
fi
if [ "$local_cfg" = "present" ]; then
ok ".compound-engineering/config.local.yaml exists"
if [ "$repo_cfg_gitignore" = "ok" ]; then
ok "Local config is gitignored"
else
warn "Local config is not safely gitignored"
project_issues=$((project_issues + 1))
fi
else
skip "No local override yet (.compound-engineering/config.local.yaml)"
fi
if [ "$scratch_gitignore" = "ok" ]; then
ok "CE scratch space is gitignored"
else
skip "CE scratch space is not gitignored"
detail "Skills that keep local scratch write it under .context/compound-engineering/"
fi
if [ "$docs_root_status" = "default" ]; then
ok "Artifact root: docs/ (default — docs_root not set)"
elif [ "$docs_root_status" = "configured" ]; then
ok "Artifact root: ${docs_root_value}/ (from ${docs_root_source})"
elif [ "$docs_root_status" = "invalid" ]; then
warn "Invalid docs_root '${docs_root_value}' in ${docs_root_source}: ${docs_root_error}"
detail "CE artifacts will not be written until docs_root is corrected or removed."
fi
if [ -n "$docs_root_local_ignored" ]; then
skip "Local docs_root '${docs_root_local_ignored}' is ignored; set docs_root only in config.yaml"
fi
if [ "$work_engine_cfg" = "native" ]; then
ok "CE Work implementation engine: native (${work_engine_detail})"
if [ -n "$work_engine_preferences_note" ]; then
if [ "$work_engine_preferences_note_level" = "warn" ]; then
warn "$work_engine_preferences_note"
else
detail "$work_engine_preferences_note"
fi
fi
elif [ "$work_engine_cfg" = "prefer" ] || [ "$work_engine_cfg" = "require" ]; then
ok "CE Work implementation engine: ${work_engine_cfg} -> ${work_engine_detail}"
elif [ "$work_engine_cfg" = "unavailable" ]; then
warn "CE Work implementation engine unavailable: ${work_engine_detail}"
elif [ "$work_engine_cfg" = "invalid" ]; then
warn "CE Work implementation engine: ${work_engine_detail}"
fi
[ -n "$work_engine_migration_note" ] && warn "$work_engine_migration_note"
if [ "$example_cfg" = "ok" ]; then
ok "Example config is current"
elif [ "$example_cfg" = "missing" ]; then
warn "Example config missing (.compound-engineering/config.example.yaml)"
project_issues=$((project_issues + 1))
elif [ "$example_cfg" = "outdated" ]; then
warn "Example config outdated (new settings available)"
project_issues=$((project_issues + 1))
fi
for key in "${retired_keys[@]}"; do
case "$key" in
plan_use_fable) warn "Retired config key '$key' — removed; use 'plan_model' instead" ;;
brainstorm_use_fable) warn "Retired config key '$key' — removed; use 'brainstorm_model' instead" ;;
fable_nudge) warn "Retired config key '$key' — removed; model elevation is always available" ;;
esac
project_issues=$((project_issues + 1))
done
# --- Compound Packs (packs: config key) -------------------------------------
section "Compound Packs"
packs_python="$(for c in python3 python py; do command -v "$c" >/dev/null 2>&1 && "$c" -c '' >/dev/null 2>&1 && { echo "$c"; break; }; done)"
packs_resolver="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/packs-resolve.py"
if [ -z "$packs_python" ]; then
skip "No Python interpreter found; pack health not checked"
elif [ ! -f "$packs_resolver" ]; then
skip "packs-resolve.py not found beside check-health; pack health not checked"
else
packs_json="$("$packs_python" "$packs_resolver" 2>/dev/null)"
if [ -z "$packs_json" ]; then
warn "packs-resolve.py failed to run"
project_issues=$((project_issues + 1))
else
packs_report="$(printf '%s' "$packs_json" | "$packs_python" -c '
import json, os, re, subprocess, sys
data = json.load(sys.stdin)
roots, errors, warns = data.get("roots", []), data.get("errors", []), data.get("warnings", [])
if not roots and not errors and not warns:
print("SKIP\tNo packs configured")
for r in roots:
line = "OK\tpack " + r["id"]
url, ref = r.get("url"), r.get("ref")
if url and ref:
line += " (" + ref + ")"
# Only a full commit id is immutable. A branch tip advances and a tag can
# be force-moved upstream, so for either compare the cached HEAD with the
# remote target of that name -- the peeled commit for an annotated tag,
# which is why the ls-remote asks for `<tag>^{}` too.
if not re.fullmatch(r"[0-9a-f]{40}|[0-9a-f]{64}", ref):
try:
genv = dict(os.environ)
genv["GIT_TERMINAL_PROMPT"] = "0"
genv.setdefault("GIT_ASKPASS", "true")
_ssh = genv.get("GIT_SSH_COMMAND") or "ssh"
if "BatchMode" not in _ssh:
genv["GIT_SSH_COMMAND"] = _ssh + " -o BatchMode=yes"
names = ["refs/tags/" + ref + "^{}", "refs/tags/" + ref, "refs/heads/" + ref]
remote = subprocess.run(["git", "ls-remote", "--end-of-options", url, *names],
capture_output=True, text=True, timeout=10, env=genv)
targets = {}
for row in remote.stdout.splitlines() if remote.returncode == 0 else []:
sha, _, name = row.partition("\t")
if name:
targets[name] = sha
rsha = next((targets[n] for n in names if n in targets), "")
local = subprocess.run(["git", "-C", r["dir"], "rev-parse", "HEAD"], capture_output=True, text=True, timeout=10)
lsha = local.stdout.strip() if local.returncode == 0 else ""
if rsha and lsha and rsha != lsha:
line += " -- cached resolution is behind upstream"
except Exception:
pass # offline or slow remote: silently skip the drift note
# Subdirectories are storage, so rule-shaped files there are a note on the
# OK line, never a warning: the author may keep drafts and evidence with frontmatter.
nested = r.get("nested_rule_shaped", 0)
if nested:
line += " -- " + str(nested) + " rule-shaped file(s) in subfolders kept as storage"
print(line)
for w in warns:
print("WARN\t" + w)
for e in errors:
print("ERROR\t" + e)
')"
while IFS=$'\t' read -r kind msg; do
[ -z "$kind" ] && continue
case "$kind" in
OK) ok "$msg" ;;
SKIP) skip "$msg" ;;
WARN) warn "$msg" ;;
ERROR) warn "Pack config error: $msg"; project_issues=$((project_issues + 1)) ;;
esac
done < <(printf '%s\n' "$packs_report")
fi
fi
else
section "Project config"
skip "Not inside a git repository"
fi
echo ""
if [ "$project_issues" -eq 0 ]; then
echo " ✅ Project config healthy. Optional capabilities available: ${capability_ok}/${capability_total}"
else
echo " ⚠️ ${project_issues} project issue(s) found. Optional capabilities available: ${capability_ok}/${capability_total}"
fi
if [ "$legacy_codex_map" = "yes" ]; then
echo " Environment: the legacy Codex tool map above still needs attention."
fi
if [ "$capability_missing" -gt 0 ]; then
echo " Missing optional tools do not block setup; install them only for the workflows you use."
fi
echo ""
SHA-256: 26f9daeec21a800033bb15186dbe08db526b4488d3084bdd18e76f6ef920da1b