Files
boshu2__agentops/scripts/test-codex-native-install.sh
T
Bo e431339c40 feat(hookless)!: remove all hooks — skills + CLI only (soc-57b7f #remove-all-hooks) (#511)
## What

AgentOps 3.0 goes **fully hookless**. This removes the entire hook
product surface — the product is now skills + the `ao` CLI with **zero
hooks**. CI is the authoritative gate.

## Deleted

- `hooks/` — 46 hook scripts + `hooks.json` + examples (whole directory)
- `cli/embedded/hooks/` + embedded `hooks.json` +
`embedded/lib/hook-helpers.sh`
- `lib/hook-helpers.sh`
- `ao hooks` CLI command: `cli/cmd/ao/hooks.go`, `hooks_run.go` + 5 hook
test files; `cli/internal/bridge/hooks.go`;
`cli/internal/doctor/fix_hooks.go` + test
- Codex hook manifest (`hooks/codex-hooks.json`) + handler/audit scripts
(`scripts/audit-codex-hooks.sh`, `install-dev-hooks.sh`,
`test-hooks-output.sh`, `test-codex-hookless-lifecycle.sh`,
`test-hookless-rpi-phased.sh`)
- Hook lease surface: `docs/contracts/hook-lease-*`,
`schemas/hook-lease.v1.schema.json`,
`scripts/check-hook-lease-inventory.sh`,
`check-hook-port-replacements.sh`, `generate-hook-lease-inventory.py`
- Hook docs: `docs/HOOKS.md`, `cli/docs/HOOKS.md`,
`docs/architecture/hook-noise-audit.md`,
`docs/contracts/hook-runtime-contract.md`
- `tests/hooks/` (whole dir) + hook test scripts; 5 hook eval suites +
fixtures

## CI gates removed

`hook-preflight`, `validate-hooks-doc-parity`, `hook-output-schema-lint`
(+ scripts/bats), the hook eval suites, the `test-runtime-codex-smoke` /
`test-codex-native-install` / `test-codex-plugin-install` hook-handler
assertions, the cli-integration hook-lifecycle steps, the bats
`tests/hooks/*` glob + orphan-hooks audit, and the `--with-hooks`
install path. `embedded-sync` now validates only lib/skills. Both
summary `needs:` lists + the summary echo +
`docs/contracts/ci-jobs.yaml` updated; `validate-ci-policy-parity`
passes (66 rows). `.codex-plugin/plugin.json` drops the "Hooks"
capability.

## Load-bearing PRESERVED (reported, not forced)

- **`cli/cmd/ao/codex_runtime.go`** — the codex runtime *lifecycle
profile* (`HookCapable`/`HookConfigured` detection) is a
runtime-capability abstraction used by 6 `validate-codex-*` CI gates,
distinct from the hook product. Deleting it is a separate refactor.
- **`hooks-authoring` skill** + `schemas/hooks-manifest.v1.schema.json`
— reframed as an opt-in "author your own hooks" guide. Deleting the
skill cascades into catalog/domain-map/dispositions/context-map golden
files (skill-count sync), out of scope for the hook-product removal.
- **`scripts/pre-push-gate.sh`** — retired local gate (not in CI);
self-skips deleted hook scripts via `[[ -x ]]` guards; its 55 bats tests
still pass.
- Domain-enforcement audit keeps the `enforced`-mode schema for
backward-compatible JSON readers, but the hookless resolver only returns
`audited`/`unavailable`.

## Verification

`go build` / `go vet` clean; `go test ./...` = **11849 passed, 0
failed** (68 pkgs). gofmt clean on all touched files. Green: registry
`--check` (0 hooks), `regen-codex-hashes --check`,
`validate-ci-policy-parity`, `check-wiring-closure`,
`validate-embedded-sync`, `validate-manifests`, `validate-agents-split`,
`doc-release` (0 broken links), `generate-cli-reference --check`,
`heal.sh --strict`, codex/claude/plugin smoke tests, baseline-audit (0
stale). Diff: 231 files, +354 / −39803.

Closes-scenario: soc-57b7f#remove-all-hooks
Bounded-context: BC5-Runtime
Evidence: .github/workflows/validate.yml
2026-05-24 11:19:37 -04:00

259 lines
9.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# test-codex-native-install.sh
# Verifies the checked-in Codex-native bundle + install flow.
#
# What it checks:
# 1) shellcheck on codex install scripts
# 2) skill integrity gate (heal --strict)
# 3) checked-in skills-codex bundle is complete
# 4) install-codex.sh succeeds into temp HOME
# 5) Installed native plugin cache contains expected skill count and required files
# 6) Codex entrypoint files are runtime-agnostic (no ~/.codex/skills hardcoding)
# 7) Generated SKILL.md files use $skill syntax (no known /skill references)
#
# Usage:
# bash scripts/test-codex-native-install.sh
# bash scripts/test-codex-native-install.sh --only research,vibe
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$REPO_ROOT"
ONLY_CSV=""
SKIP_LINT="false"
usage() {
cat <<'EOF'
test-codex-native-install.sh
Options:
--only <a,b,c> Test only selected skills
--skip-lint Skip shellcheck + markdownlint
--help Show this help
Examples:
bash scripts/test-codex-native-install.sh
bash scripts/test-codex-native-install.sh --only research,vibe
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--only)
ONLY_CSV="${2:-}"
shift 2
;;
--skip-lint)
SKIP_LINT="true"
shift 1
;;
--help|-h)
usage
exit 0
;;
*)
echo "Unknown arg: $1" >&2
usage >&2
exit 2
;;
esac
done
fail() {
echo "FAIL: $*" >&2
exit 1
}
info() {
echo "INFO: $*"
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "Required command not found: $1"
}
require_file() {
[[ -f "$1" ]] || fail "Required file missing: $1"
}
INSTALL_SCRIPT="$REPO_ROOT/scripts/install-codex-plugin.sh"
PUBLIC_INSTALL_SCRIPT="$REPO_ROOT/scripts/install-codex.sh"
HEAL_SCRIPT="$REPO_ROOT/skills/heal-skill/scripts/heal.sh"
CODEX_MANIFEST="$REPO_ROOT/.codex-plugin/plugin.json"
CODEX_MARKETPLACE="$REPO_ROOT/plugins/marketplace.json"
CODEX_SKILL_MANIFEST="$REPO_ROOT/skills-codex/.agentops-manifest.json"
require_file "$INSTALL_SCRIPT"
require_file "$PUBLIC_INSTALL_SCRIPT"
require_file "$HEAL_SCRIPT"
require_file "$CODEX_MANIFEST"
require_file "$CODEX_MARKETPLACE"
require_file "$CODEX_SKILL_MANIFEST"
require_cmd bash
require_cmd find
require_cmd awk
require_cmd sed
require_cmd jq
require_cmd rg
if [[ "$SKIP_LINT" != "true" ]]; then
require_cmd shellcheck
require_cmd markdownlint
info "Running shellcheck on codex install scripts"
shellcheck "$INSTALL_SCRIPT" "$PUBLIC_INSTALL_SCRIPT"
info "Running markdownlint on install docs"
markdownlint \
README.md \
AGENTS.md \
docs/reference.md \
docs/CONTRIBUTING.md \
docs/ARCHITECTURE.md \
docs/troubleshooting.md \
docs/INCIDENT-RUNBOOK.md
fi
info "Running strict skill integrity gate"
bash "$HEAL_SCRIPT" --strict >/dev/null
info "Checking checked-in Codex-native bundle"
[[ -s "$CODEX_SKILL_MANIFEST" ]] || fail "Checked-in Codex manifest is empty: $CODEX_SKILL_MANIFEST"
timestamp="$(date +%Y%m%d-%H%M%S)"
HOME_ROOT="/tmp/codex-native-install-test-${timestamp}"
CODEX_HOME="$HOME_ROOT/.codex"
PLUGIN_ROOT="$CODEX_HOME/plugins/cache/agentops-marketplace/agentops/local"
PLUGIN_SKILLS="$PLUGIN_ROOT/skills-codex"
info "Installing AgentOps via the public Codex installer into temp HOME"
HOME="$HOME_ROOT" AGENTOPS_BUNDLE_ROOT="$REPO_ROOT" AGENTOPS_INSTALL_REF="test-local" \
bash "$PUBLIC_INSTALL_SCRIPT" >/dev/null
[[ -d "$PLUGIN_SKILLS" ]] || fail "Plugin skills directory not created: $PLUGIN_SKILLS"
expected_count=0
if [[ -n "$ONLY_CSV" ]]; then
IFS=',' read -r -a selected <<<"$ONLY_CSV"
for skill in "${selected[@]}"; do
skill="$(echo "$skill" | xargs)"
[[ -n "$skill" ]] || continue
[[ -d "$REPO_ROOT/skills-codex/$skill" ]] || fail "Converted skill not found: skills-codex/$skill"
expected_count=$((expected_count + 1))
done
else
expected_count="$(find "$REPO_ROOT/skills-codex" -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d ' ')"
fi
installed_count="$(find "$PLUGIN_SKILLS" -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d ' ')"
[[ "$installed_count" == "$expected_count" ]] || fail "Installed count mismatch (expected $expected_count, got $installed_count)"
[[ ! -e "$HOME_ROOT/.agents/skills" ]] || fail "Unexpected ~/.agents/skills raw mirror created"
[[ ! -e "$CODEX_HOME/skills" ]] || fail "Unexpected ~/.codex/skills raw mirror created"
info "Verifying installed plugin files"
while IFS= read -r skill_dir; do
[[ -n "$skill_dir" ]] || continue
[[ -f "$skill_dir/SKILL.md" ]] || fail "Missing SKILL.md in $skill_dir"
[[ -f "$skill_dir/prompt.md" ]] || fail "Missing prompt.md in $skill_dir"
head -n 1 "$skill_dir/SKILL.md" | rg -q '^---$' || fail "Missing YAML frontmatter in $skill_dir/SKILL.md"
done < <(find "$PLUGIN_SKILLS" -mindepth 1 -maxdepth 1 -type d | sort)
[[ -f "$CODEX_HOME/config.toml" ]] || fail "Missing config.toml in $CODEX_HOME"
rg -q '^\[features\]$' "$CODEX_HOME/config.toml" || fail "config.toml missing [features] section"
rg -q '^plugins = true$' "$CODEX_HOME/config.toml" || fail "config.toml missing plugins = true"
rg -q '^\[ui\]$' "$CODEX_HOME/config.toml" || fail "config.toml missing [ui] section"
rg -q '^suppress_unstable_features_warning = true$' "$CODEX_HOME/config.toml" || fail "config.toml missing suppress_unstable_features_warning = true"
rg -q '^\[plugins\."agentops@agentops-marketplace"\]$' "$CODEX_HOME/config.toml" || fail "config.toml missing AgentOps plugin block"
rg -q '^enabled = true$' "$CODEX_HOME/config.toml" || fail "config.toml missing enabled = true"
if rg -q '^hooks = true$' "$CODEX_HOME/config.toml"; then
fail "default install should not enable hooks = true"
fi
if rg -q '^codex_hooks[[:space:]]*=' "$CODEX_HOME/config.toml"; then
fail "config.toml still contains deprecated codex_hooks"
fi
[[ ! -f "$CODEX_HOME/hooks.json" ]] || fail "Default install should not create ~/.codex/hooks.json"
rg -q '"install_mode": "native-plugin"' "$CODEX_HOME/.agentops-codex-install.json" \
|| fail "install metadata missing native-plugin mode"
rg -q '"hook_runtime": "hookless-default"' "$CODEX_HOME/.agentops-codex-install.json" \
|| fail "install metadata missing hookless-default hook_runtime field"
rg -q '"hooks_installed": false' "$CODEX_HOME/.agentops-codex-install.json" \
|| fail "install metadata should record hooks_installed=false"
rg -q '"user_skills_root": null' "$CODEX_HOME/.agentops-codex-install.json" \
|| fail "install metadata should not record a raw skills mirror"
info "Verifying --codex-home installs into the target Codex home (hookless)"
EXPLICIT_HOME_ROOT="/tmp/codex-native-plugin-explicit-${timestamp}"
EXPLICIT_CODEX_HOME="${EXPLICIT_HOME_ROOT}/explicit/.codex"
REAL_HOME_ROOT="${EXPLICIT_HOME_ROOT}/real-home"
mkdir -p "$EXPLICIT_CODEX_HOME"
HOME="$REAL_HOME_ROOT" bash "$INSTALL_SCRIPT" \
--repo-root "$REPO_ROOT" \
--codex-home "$EXPLICIT_CODEX_HOME" \
--version "test-local" \
--update-command "test-local" >/dev/null
[[ ! -f "$EXPLICIT_CODEX_HOME/hooks.json" ]] || fail "hookless install must not create hooks.json under --codex-home"
[[ -f "$EXPLICIT_CODEX_HOME/.agentops-codex-install.json" ]] || fail "install metadata missing under --codex-home"
rg -q '"hooks_installed": false' "$EXPLICIT_CODEX_HOME/.agentops-codex-install.json" \
|| fail "explicit install metadata should record hooks_installed=false"
info "Checking Codex entrypoint files for runtime-agnostic instructions"
entrypoint_files=()
while IFS= read -r -d '' file; do
entrypoint_files+=("$file")
done < <(find "$REPO_ROOT/skills-codex" -type f \( -name "SKILL.md" -o -name "prompt.md" \) -print0)
if rg -n "\$HOME/.codex/skills|~/.codex/skills" "${entrypoint_files[@]}" >/dev/null 2>&1; then
fail "Found stale ~/.codex/skills references in Codex entrypoint files"
fi
# Build regex alternation from known converted skill names.
skill_pattern="$(
find "$REPO_ROOT/skills-codex" -mindepth 1 -maxdepth 1 -type d -exec basename {} \; \
| sort \
| awk '
BEGIN { ORS="" }
{
gsub(/[][(){}.^$*+?|\\-]/, "\\\\&", $0)
if (NR > 1) { printf "|" }
printf "%s", $0
}
'
)"
[[ -n "$skill_pattern" ]] || fail "Could not build skill-name regex for slash-command check"
info "Checking Codex entrypoint files for known slash-command references"
if [[ "${#entrypoint_files[@]}" -eq 0 ]]; then
fail "No Codex entrypoint files found for slash-command check"
fi
if rg --pcre2 -n "(^|[^A-Za-z0-9_./])/(${skill_pattern})(?![A-Za-z0-9-])" "${entrypoint_files[@]}" >/dev/null 2>&1; then
fail "Found known /skill command references in skills-codex output"
fi
info "Checking openai-docs Codex install flow for duplicate setup drift"
openai_skill="$REPO_ROOT/skills-codex/openai-docs/SKILL.md"
legacy_codex_settings_pattern="~"
legacy_codex_settings_pattern="${legacy_codex_settings_pattern}/.codex/settings.json"
require_file "$openai_skill"
[[ "$(rg -c '^\*\*In Codex:\*\*$' "$openai_skill")" == "1" ]] \
|| fail "Expected exactly one '**In Codex:**' section in $openai_skill"
rg -q 'codex mcp add openaiDeveloperDocs --url https://developers.openai.com/mcp' "$openai_skill" \
|| fail "Missing Codex MCP install command in $openai_skill"
if rg -q "$legacy_codex_settings_pattern" "$openai_skill"; then
fail "Found duplicate Codex settings-file install flow in $openai_skill"
fi
info "Checking shared Codex backend references"
shared_skill="$REPO_ROOT/skills-codex/shared/SKILL.md"
require_file "$shared_skill"
rg -q '\| Codex session agents \| `references/backend-codex-subagents\.md` \|' "$shared_skill" \
|| fail "Missing Codex session-agent backend mapping in $shared_skill"
echo ""
echo "PASS: Codex-native install flow verified"
echo " skills tested: $installed_count"
echo " home root: $HOME_ROOT"
echo " plugin root: $PLUGIN_ROOT"