140 lines
5.5 KiB
Bash
Executable File
140 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Dev-Docker verify — SOP artifact for PPLAN dev-docker runs.
|
|
# Runs INSIDE the container (aipass-test image): real GitHub clone of the
|
|
# dev branch, one-command install, then asserts provider hook wiring and
|
|
# live-fires the SessionStart cadence reset + misroute guidance.
|
|
#
|
|
# Host invocation:
|
|
# docker run --rm -v "$AIPASS_HOME/tests/docker_dev_verify.sh":/verify.sh:ro \
|
|
# aipass-test:latest bash /verify.sh
|
|
#
|
|
# Supersedes docker_clone_test.sh (pre-bridge architecture, stale).
|
|
#
|
|
set -uo pipefail
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
ok() { echo " OK $1"; PASS=$((PASS+1)); }
|
|
bad() { echo " FAIL $1"; FAIL=$((FAIL+1)); }
|
|
|
|
echo "========================================="
|
|
echo " AIPass Dev-Docker Verify (bridge era)"
|
|
echo "========================================="
|
|
|
|
# --- Phase 1: real clone of dev ---
|
|
echo "--- Phase 1: clone dev from GitHub ---"
|
|
rm -rf "$HOME/workspace" && mkdir -p "$HOME/workspace" && cd "$HOME/workspace"
|
|
if git clone -b dev --depth 1 https://github.com/AIOSAI/AIPass.git 2>&1 | tail -2; then
|
|
ok "clone dev"
|
|
else
|
|
bad "clone dev"
|
|
echo "Cannot continue without a clone."
|
|
exit 1
|
|
fi
|
|
cd AIPass
|
|
echo " HEAD: $(git log -1 --oneline)"
|
|
|
|
# --- Phase 2: one-command install ---
|
|
echo "--- Phase 2: ./aipass install ---"
|
|
if ./aipass install 2>&1 | tail -15; then
|
|
ok "installer exit 0"
|
|
else
|
|
bad "installer exited non-zero"
|
|
fi
|
|
|
|
SETTINGS="$HOME/.claude/settings.json"
|
|
AH="$HOME/workspace/AIPass"
|
|
VPY="$AH/.venv/bin/python3"
|
|
BRIDGE="$AH/src/aipass/hooks/apps/handlers/bridges/claude.py"
|
|
|
|
# --- Phase 3: provider settings assertions ---
|
|
echo "--- Phase 3: provider settings ---"
|
|
if [ -f "$SETTINGS" ]; then ok "settings.json exists"; else bad "settings.json missing"; fi
|
|
|
|
if jq -e '.hooks.SessionStart' "$SETTINGS" > /dev/null 2>&1; then
|
|
ok "SessionStart event wired"
|
|
else
|
|
bad "SessionStart event missing"
|
|
fi
|
|
|
|
SS_CMD=$(jq -r '.hooks.SessionStart[0].hooks[0].command // ""' "$SETTINGS" 2>/dev/null)
|
|
case "$SS_CMD" in
|
|
*"bridges/claude.py SessionStart:cadence_reset"*) ok "SessionStart command = bridge cadence_reset" ;;
|
|
*) bad "SessionStart command wrong: $SS_CMD" ;;
|
|
esac
|
|
|
|
SS_TO=$(jq -r '.hooks.SessionStart[0].hooks[0].timeout // 0' "$SETTINGS" 2>/dev/null)
|
|
if [ "$SS_TO" = "30" ]; then ok "SessionStart timeout 30"; else bad "SessionStart timeout: $SS_TO"; fi
|
|
|
|
if jq -e '.env.AIPASS_HOME' "$SETTINGS" > /dev/null 2>&1; then
|
|
ok "AIPASS_HOME in settings env"
|
|
else
|
|
bad "AIPASS_HOME missing from settings env"
|
|
fi
|
|
|
|
UPS=$(jq -r '.hooks.UserPromptSubmit | length' "$SETTINGS" 2>/dev/null || echo 0)
|
|
if [ "$UPS" -ge 6 ]; then ok "UserPromptSubmit: $UPS entries"; else bad "UserPromptSubmit: $UPS entries (want >=6)"; fi
|
|
|
|
PC=$(jq -r '.hooks.PreCompact | length' "$SETTINGS" 2>/dev/null || echo 0)
|
|
if [ "$PC" -eq 6 ]; then ok "PreCompact: 6 entries"; else bad "PreCompact: $PC entries (want 6)"; fi
|
|
|
|
# --- Phase 4: project hook config ---
|
|
echo "--- Phase 4: project hook config ---"
|
|
if jq -e '.SessionStart.cadence_reset.enabled == true' "$AH/.aipass/hooks.json" > /dev/null 2>&1; then
|
|
ok ".aipass/hooks.json SessionStart.cadence_reset enabled"
|
|
else
|
|
bad ".aipass/hooks.json SessionStart.cadence_reset missing/disabled"
|
|
fi
|
|
if jq -e '.SessionStart.cadence_reset.enabled == true' "$AH/.aipass/project_hooks.json" > /dev/null 2>&1; then
|
|
ok "project_hooks.json template has SessionStart"
|
|
else
|
|
bad "project_hooks.json template missing SessionStart"
|
|
fi
|
|
|
|
# --- Phase 5: live-fire cadence reset ---
|
|
echo "--- Phase 5: live-fire SessionStart ---"
|
|
export AIPASS_HOME="$AH"
|
|
TMPD=$("$VPY" -c "import tempfile; print(tempfile.gettempdir())")
|
|
|
|
echo '{"source":"startup","session_id":"dockerstartup"}' | "$VPY" "$BRIDGE" SessionStart:cadence_reset
|
|
TURN=$(jq -r '.turn // "none"' "$TMPD/aipass-cadence-dockerstartup.json" 2>/dev/null || echo "none")
|
|
if [ "$TURN" = "-1" ]; then ok "startup reset -> turn -1"; else bad "startup reset: turn=$TURN"; fi
|
|
|
|
echo '{"source":"resume","session_id":"dockerresume"}' | "$VPY" "$BRIDGE" SessionStart:cadence_reset
|
|
if [ ! -f "$TMPD/aipass-cadence-dockerresume.json" ]; then
|
|
ok "resume skipped (no state written)"
|
|
else
|
|
bad "resume wrote state (should skip)"
|
|
fi
|
|
|
|
PERIODS=$("$VPY" -c "
|
|
from aipass.hooks.apps.modules.cadence import _load_config
|
|
c = _load_config()
|
|
t = c['loaders']['tier0'].get('period', c['period'])
|
|
n = c['loaders']['navmap'].get('period', c['period'])
|
|
print(t, n)" 2>/dev/null)
|
|
if [ "$PERIODS" = "5 5" ]; then ok "cadence periods tier0=5 navmap=5"; else bad "cadence periods: $PERIODS (want '5 5')"; fi
|
|
|
|
# --- Phase 6: misroute guidance (guide, never crash) ---
|
|
echo "--- Phase 6: misroute guidance ---"
|
|
DRONE="$AH/.venv/bin/drone"
|
|
AIPASS_BIN="$AH/.venv/bin/aipass"
|
|
|
|
OUT=$("$DRONE" aipass 2>&1 || true)
|
|
if echo "$OUT" | grep -qi "traceback"; then bad "'drone aipass' crashed"; else ok "'drone aipass' no crash"; fi
|
|
if echo "$OUT" | grep -qi "aipass"; then ok "'drone aipass' mentions aipass guidance"; else bad "'drone aipass' output unhelpful"; fi
|
|
|
|
OUT=$("$DRONE" @aipass 2>&1 || true)
|
|
if echo "$OUT" | grep -qi "traceback"; then bad "'drone @aipass' crashed"; else ok "'drone @aipass' no crash"; fi
|
|
|
|
OUT=$("$AIPASS_BIN" @drone 2>&1 || true)
|
|
if echo "$OUT" | grep -qi "traceback"; then bad "'aipass @drone' crashed"; else ok "'aipass @drone' no crash"; fi
|
|
if echo "$OUT" | grep -qi "drone"; then ok "'aipass @drone' mentions drone guidance"; else bad "'aipass @drone' output unhelpful"; fi
|
|
|
|
# --- Summary ---
|
|
echo "========================================="
|
|
echo " Results: $PASS passed, $FAIL failed"
|
|
echo "========================================="
|
|
[ "$FAIL" -eq 0 ]
|