mirror of
https://github.com/obra/superpowers.git
synced 2026-11-07 07:28:10 +00:00
The V2 plugin registered its bootstrap injector only on
ctx.session.hook('context'). OpenCode 2 prepares each model request kind
through its own hook: normal agent turns through `context`, the
compaction (summary) request through `compaction`, and session-scoped
one-shot generation through `generate`
(packages/core/src/session/model-request.ts). Every built-in V2 plugin
registers its handler on all three, and the upstream V1 migration guide
says to do the same when a transform must apply to every request kind.
So the compaction request's first user message lacked the bootstrap
that every prior turn carried, and the prompt diverged right after
system + tools. On a provider with prefix caching that is a cold
re-prefill of the whole session on its largest request (#2391).
Reproduced on real OpenCode 2.1.2 and 2.1.3 with a scripted stub model
that pushes the session over the compaction ceiling: before, the
compaction request shares 26.5k of 30.8k serialized chars with the
previous agent request and differs at the first user message; after,
the previous request is a full prefix of the compaction request.
The handler body is unchanged (child-session skip, idempotence guard,
checkpoint-only append), lifted into a named function and registered on
all three hooks, each in its own try/catch. Based on PR #2409.
Fixes #2391
Co-authored-by: Aashish <145881415+aashish254@users.noreply.github.com>
Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba
171 lines
4.6 KiB
Bash
Executable file
171 lines
4.6 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Main test runner for OpenCode plugin test suite
|
|
# Runs all tests and reports results
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
echo "========================================"
|
|
echo " OpenCode Plugin Test Suite"
|
|
echo "========================================"
|
|
echo ""
|
|
echo "Repository: $(cd ../.. && pwd)"
|
|
echo "Test time: $(date)"
|
|
echo ""
|
|
|
|
# Parse command line arguments
|
|
RUN_INTEGRATION=false
|
|
VERBOSE=false
|
|
SPECIFIC_TEST=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--integration|-i)
|
|
RUN_INTEGRATION=true
|
|
shift
|
|
;;
|
|
--verbose|-v)
|
|
VERBOSE=true
|
|
shift
|
|
;;
|
|
--test|-t)
|
|
SPECIFIC_TEST="$2"
|
|
shift 2
|
|
;;
|
|
--help|-h)
|
|
echo "Usage: $0 [options]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --integration, -i Run integration tests (requires OpenCode)"
|
|
echo " --verbose, -v Show verbose output"
|
|
echo " --test, -t NAME Run only the specified test"
|
|
echo " --help, -h Show this help"
|
|
echo ""
|
|
echo "Tests:"
|
|
echo " test-plugin-loading.sh Verify plugin installation and structure"
|
|
echo " test-bootstrap-caching.sh Verify bootstrap content caching"
|
|
echo " test-session-bootstrap.sh Verify session classification and lookup recovery"
|
|
echo " test-hook-registration.sh Verify V2 bootstrap registers on context, compaction, generate"
|
|
echo " test-skill-registration.sh Verify V2 skill registration contract (2.0.4 path field)"
|
|
echo " test-tools.sh Test use_skill and find_skills tools (integration)"
|
|
echo " test-priority.sh Test skill priority resolution (integration)"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
echo "Use --help for usage information"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# List of tests to run (no external dependencies)
|
|
tests=(
|
|
"test-plugin-loading.sh"
|
|
"test-bootstrap-caching.sh"
|
|
"test-session-bootstrap.sh"
|
|
"test-hook-registration.sh"
|
|
"test-skill-registration.sh"
|
|
)
|
|
|
|
# Integration tests (require OpenCode)
|
|
integration_tests=(
|
|
"test-tools.sh"
|
|
"test-priority.sh"
|
|
)
|
|
|
|
# Add integration tests if requested
|
|
if [ "$RUN_INTEGRATION" = true ]; then
|
|
tests+=("${integration_tests[@]}")
|
|
fi
|
|
|
|
# Filter to specific test if requested
|
|
if [ -n "$SPECIFIC_TEST" ]; then
|
|
tests=("$SPECIFIC_TEST")
|
|
fi
|
|
|
|
# Track results
|
|
passed=0
|
|
failed=0
|
|
skipped=0
|
|
|
|
# Run each test
|
|
for test in "${tests[@]}"; do
|
|
echo "----------------------------------------"
|
|
echo "Running: $test"
|
|
echo "----------------------------------------"
|
|
|
|
test_path="$SCRIPT_DIR/$test"
|
|
|
|
if [ ! -f "$test_path" ]; then
|
|
echo " [SKIP] Test file not found: $test"
|
|
skipped=$((skipped + 1))
|
|
continue
|
|
fi
|
|
|
|
if [ ! -x "$test_path" ]; then
|
|
echo " Making $test executable..."
|
|
chmod +x "$test_path"
|
|
fi
|
|
|
|
start_time=$(date +%s)
|
|
|
|
if [ "$VERBOSE" = true ]; then
|
|
if bash "$test_path"; then
|
|
end_time=$(date +%s)
|
|
duration=$((end_time - start_time))
|
|
echo ""
|
|
echo " [PASS] $test (${duration}s)"
|
|
passed=$((passed + 1))
|
|
else
|
|
end_time=$(date +%s)
|
|
duration=$((end_time - start_time))
|
|
echo ""
|
|
echo " [FAIL] $test (${duration}s)"
|
|
failed=$((failed + 1))
|
|
fi
|
|
else
|
|
# Capture output for non-verbose mode
|
|
if output=$(bash "$test_path" 2>&1); then
|
|
end_time=$(date +%s)
|
|
duration=$((end_time - start_time))
|
|
echo " [PASS] (${duration}s)"
|
|
passed=$((passed + 1))
|
|
else
|
|
end_time=$(date +%s)
|
|
duration=$((end_time - start_time))
|
|
echo " [FAIL] (${duration}s)"
|
|
echo ""
|
|
echo " Output:"
|
|
echo "$output" | sed 's/^/ /'
|
|
failed=$((failed + 1))
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
done
|
|
|
|
# Print summary
|
|
echo "========================================"
|
|
echo " Test Results Summary"
|
|
echo "========================================"
|
|
echo ""
|
|
echo " Passed: $passed"
|
|
echo " Failed: $failed"
|
|
echo " Skipped: $skipped"
|
|
echo ""
|
|
|
|
if [ "$RUN_INTEGRATION" = false ] && [ ${#integration_tests[@]} -gt 0 ]; then
|
|
echo "Note: Integration tests were not run."
|
|
echo "Use --integration flag to run tests that require OpenCode."
|
|
echo ""
|
|
fi
|
|
|
|
if [ $failed -gt 0 ]; then
|
|
echo "STATUS: FAILED"
|
|
exit 1
|
|
else
|
|
echo "STATUS: PASSED"
|
|
exit 0
|
|
fi
|