chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 11:55:25 +08:00
commit 6cfe3b4a67
173 changed files with 35323 additions and 0 deletions
+165
View File
@@ -0,0 +1,165 @@
#!/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-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"
)
# 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
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
# Setup script for OpenCode plugin tests
# Creates an isolated test environment with proper plugin installation
set -euo pipefail
# Get the repository root (two levels up from tests/opencode/)
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
# Create temp home directory for isolation
export TEST_HOME
TEST_HOME=$(mktemp -d)
export HOME="$TEST_HOME"
export XDG_CONFIG_HOME="$TEST_HOME/.config"
export OPENCODE_CONFIG_DIR="$TEST_HOME/.config/opencode"
# Standard install layout:
# $OPENCODE_CONFIG_DIR/superpowers/ ← package root
# $OPENCODE_CONFIG_DIR/superpowers/skills/ ← skills dir (../../skills from plugin)
# $OPENCODE_CONFIG_DIR/superpowers/.opencode/plugins/superpowers.js ← plugin file
# $OPENCODE_CONFIG_DIR/plugins/superpowers.js ← symlink OpenCode reads
SUPERPOWERS_DIR="$OPENCODE_CONFIG_DIR/superpowers"
SUPERPOWERS_SKILLS_DIR="$SUPERPOWERS_DIR/skills"
SUPERPOWERS_PLUGIN_FILE="$SUPERPOWERS_DIR/.opencode/plugins/superpowers.js"
# Install skills
mkdir -p "$SUPERPOWERS_DIR"
cp -r "$REPO_ROOT/skills" "$SUPERPOWERS_DIR/"
# Install plugin
mkdir -p "$(dirname "$SUPERPOWERS_PLUGIN_FILE")"
cp "$REPO_ROOT/.opencode/plugins/superpowers.js" "$SUPERPOWERS_PLUGIN_FILE"
# Register plugin via symlink (what OpenCode actually reads)
mkdir -p "$OPENCODE_CONFIG_DIR/plugins"
ln -sf "$SUPERPOWERS_PLUGIN_FILE" "$OPENCODE_CONFIG_DIR/plugins/superpowers.js"
# Create test skills in different locations for testing
# Personal test skill
mkdir -p "$OPENCODE_CONFIG_DIR/skills/personal-test"
cat > "$OPENCODE_CONFIG_DIR/skills/personal-test/SKILL.md" <<'EOF'
---
name: personal-test
description: Test personal skill for verification
---
# Personal Test Skill
This is a personal skill used for testing.
PERSONAL_SKILL_MARKER_12345
EOF
# Create a project directory for project-level skill tests
mkdir -p "$TEST_HOME/test-project/.opencode/skills/project-test"
cat > "$TEST_HOME/test-project/.opencode/skills/project-test/SKILL.md" <<'EOF'
---
name: project-test
description: Test project skill for verification
---
# Project Test Skill
This is a project skill used for testing.
PROJECT_SKILL_MARKER_67890
EOF
echo "Setup complete: $TEST_HOME"
echo "OPENCODE_CONFIG_DIR: $OPENCODE_CONFIG_DIR"
echo "Superpowers dir: $SUPERPOWERS_DIR"
echo "Skills dir: $SUPERPOWERS_SKILLS_DIR"
echo "Plugin file: $SUPERPOWERS_PLUGIN_FILE"
echo "Plugin registered at: $OPENCODE_CONFIG_DIR/plugins/superpowers.js"
echo "Test project at: $TEST_HOME/test-project"
# Helper function for cleanup (call from tests or trap)
cleanup_test_env() {
if [ -n "${TEST_HOME:-}" ] && [ -d "$TEST_HOME" ]; then
rm -rf "$TEST_HOME"
fi
}
# Export for use in tests
export -f cleanup_test_env
export REPO_ROOT
export SUPERPOWERS_DIR
export SUPERPOWERS_SKILLS_DIR
export SUPERPOWERS_PLUGIN_FILE
+146
View File
@@ -0,0 +1,146 @@
import fs from 'fs';
import { pathToFileURL } from 'url';
const [, , pluginPath, scenario] = process.argv;
if (!pluginPath || !['present', 'missing'].includes(scenario)) {
console.error('Usage: node test-bootstrap-caching.mjs PLUGIN_PATH present|missing');
process.exit(2);
}
let existsCount = 0;
let readCount = 0;
const originalExistsSync = fs.existsSync;
const originalReadFileSync = fs.readFileSync;
fs.existsSync = function (...args) {
if (isBootstrapSkillPath(args[0])) {
existsCount += 1;
}
return originalExistsSync.apply(this, args);
};
fs.readFileSync = function (...args) {
if (isBootstrapSkillPath(args[0])) {
readCount += 1;
}
return originalReadFileSync.apply(this, args);
};
const mod = await import(pathToFileURL(pluginPath).href);
const plugin = await mod.SuperpowersPlugin({ client: {}, directory: '.' });
const transform = plugin['experimental.chat.messages.transform'];
const firstOutput = makeOutput(`${scenario} bootstrap first step`);
await transform({}, firstOutput);
const afterFirst = { existsCount, readCount };
const secondOutput = makeOutput(`${scenario} bootstrap second step`);
await transform({}, secondOutput);
const afterSecond = { existsCount, readCount };
const result = {
scenario,
firstBootstrapParts: countBootstrapParts(firstOutput),
secondBootstrapParts: countBootstrapParts(secondOutput),
staleMentionMapping: bootstrapText(firstOutput).includes('@mention'),
staleTaskMapping: bootstrapText(firstOutput).includes('`Task` tool with subagents'),
mapsSubagentToTask: bootstrapText(firstOutput).includes('`task` with `subagent_type: "general"`'),
mapsMutationToApplyPatch: bootstrapText(firstOutput).includes('`apply_patch`'),
firstReadCount: afterFirst.readCount,
secondReadCount: afterSecond.readCount,
firstExistsCount: afterFirst.existsCount,
secondExistsCount: afterSecond.existsCount,
};
const failures = scenario === 'present'
? assertPresentBootstrap(result)
: assertMissingBootstrap(result);
if (failures.length > 0) {
console.error(JSON.stringify(result, null, 2));
for (const failure of failures) {
console.error(`FAIL: ${failure}`);
}
process.exit(1);
}
console.log(JSON.stringify(result, null, 2));
function isBootstrapSkillPath(filePath) {
return String(filePath).replaceAll('\\', '/').includes('using-superpowers/SKILL.md');
}
function makeOutput(text) {
return {
messages: [{
info: { role: 'user' },
parts: [{ type: 'text', text }],
}],
};
}
function countBootstrapParts(output) {
return output.messages[0].parts.filter(
(part) => part.type === 'text' && part.text.includes('EXTREMELY_IMPORTANT')
).length;
}
function bootstrapText(output) {
return output.messages[0].parts.find(
(part) => part.type === 'text' && part.text.includes('EXTREMELY_IMPORTANT')
)?.text || '';
}
function assertPresentBootstrap(result) {
const failures = [];
if (result.firstBootstrapParts !== 1) {
failures.push(`expected first transform to inject one bootstrap part, got ${result.firstBootstrapParts}`);
}
if (result.secondBootstrapParts !== 1) {
failures.push(`expected second transform to inject one bootstrap part, got ${result.secondBootstrapParts}`);
}
if (result.firstReadCount !== 1) {
failures.push(`expected first transform to read SKILL.md once, got ${result.firstReadCount}`);
}
if (result.secondReadCount !== result.firstReadCount) {
failures.push(`expected cached second transform to do no additional reads, got ${result.secondReadCount - result.firstReadCount}`);
}
if (result.secondExistsCount !== result.firstExistsCount) {
failures.push(`expected cached second transform to do no additional exists checks, got ${result.secondExistsCount - result.firstExistsCount}`);
}
if (result.staleMentionMapping) {
failures.push('expected OpenCode bootstrap not to teach @mention subagent syntax');
}
if (result.staleTaskMapping) {
failures.push('expected OpenCode bootstrap not to teach stale Task-tool mapping');
}
if (!result.mapsSubagentToTask) {
failures.push('expected OpenCode bootstrap to map general-purpose subagents to task with subagent_type');
}
if (!result.mapsMutationToApplyPatch) {
failures.push('expected OpenCode bootstrap to map file mutation to apply_patch');
}
return failures;
}
function assertMissingBootstrap(result) {
const failures = [];
if (result.firstBootstrapParts !== 0) {
failures.push(`expected no bootstrap when SKILL.md is missing, got ${result.firstBootstrapParts}`);
}
if (result.secondBootstrapParts !== 0) {
failures.push(`expected no bootstrap on second missing-file transform, got ${result.secondBootstrapParts}`);
}
if (result.firstReadCount !== 0 || result.secondReadCount !== 0) {
failures.push(`expected missing file path to avoid reads, got ${result.secondReadCount}`);
}
if (result.firstExistsCount < 1) {
failures.push('expected first transform to check whether SKILL.md exists');
}
if (result.secondExistsCount !== result.firstExistsCount) {
failures.push(`expected missing-file result to be cached, got ${result.secondExistsCount - result.firstExistsCount} extra exists checks`);
}
return failures;
}
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Test: Bootstrap Content Caching (#1202)
# Verifies the OpenCode transform caches bootstrap content between agent steps.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo "=== Test: Bootstrap Content Caching (#1202) ==="
source "$SCRIPT_DIR/setup.sh"
trap cleanup_test_env EXIT
run_present_file_check() {
node "$SCRIPT_DIR/test-bootstrap-caching.mjs" "$SUPERPOWERS_PLUGIN_FILE" present
}
run_missing_file_check() {
mv "$SUPERPOWERS_SKILLS_DIR/using-superpowers/SKILL.md" "$TEST_HOME/using-superpowers.SKILL.md.bak"
node "$SCRIPT_DIR/test-bootstrap-caching.mjs" "$SUPERPOWERS_PLUGIN_FILE" missing
}
echo "Test 1: Caches bootstrap after the first successful transform..."
run_present_file_check
echo " [PASS] Bootstrap content is cached while fresh message arrays still receive injection"
echo "Test 2: Caches missing SKILL.md result..."
run_missing_file_check
echo " [PASS] Missing bootstrap file is cached and not re-probed every transform"
echo ""
echo "=== All bootstrap caching tests passed ==="
+82
View File
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
# Test: Plugin Loading
# Verifies that the superpowers plugin loads correctly in OpenCode
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo "=== Test: Plugin Loading ==="
# Source setup to create isolated environment
source "$SCRIPT_DIR/setup.sh"
# Trap to cleanup on exit
trap cleanup_test_env EXIT
plugin_link="$OPENCODE_CONFIG_DIR/plugins/superpowers.js"
# Test 1: Verify plugin file exists and is registered
echo "Test 1: Checking plugin registration..."
if [ -L "$plugin_link" ]; then
echo " [PASS] Plugin symlink exists"
else
echo " [FAIL] Plugin symlink not found at $plugin_link"
exit 1
fi
# Verify symlink target exists
if [ -f "$(readlink -f "$plugin_link")" ]; then
echo " [PASS] Plugin symlink target exists"
else
echo " [FAIL] Plugin symlink target does not exist"
exit 1
fi
# Test 2: Verify skills directory is populated
echo "Test 2: Checking skills directory..."
skill_count=$(find "$SUPERPOWERS_SKILLS_DIR" -name "SKILL.md" | wc -l)
if [ "$skill_count" -gt 0 ]; then
echo " [PASS] Found $skill_count skills"
else
echo " [FAIL] No skills found in $SUPERPOWERS_SKILLS_DIR"
exit 1
fi
# Test 3: Check using-superpowers skill exists (critical for bootstrap)
echo "Test 3: Checking using-superpowers skill (required for bootstrap)..."
if [ -f "$SUPERPOWERS_SKILLS_DIR/using-superpowers/SKILL.md" ]; then
echo " [PASS] using-superpowers skill exists"
else
echo " [FAIL] using-superpowers skill not found (required for bootstrap)"
exit 1
fi
# Test 4: Verify plugin JavaScript syntax (basic check)
echo "Test 4: Checking plugin JavaScript syntax..."
if node --check "$SUPERPOWERS_PLUGIN_FILE" 2>/dev/null; then
echo " [PASS] Plugin JavaScript syntax is valid"
else
echo " [FAIL] Plugin has JavaScript syntax errors"
exit 1
fi
# Test 5: Verify bootstrap text does not reference a hardcoded skills path
echo "Test 5: Checking bootstrap does not advertise a wrong skills path..."
if grep -q 'configDir}/skills/superpowers/' "$SUPERPOWERS_PLUGIN_FILE"; then
echo " [FAIL] Plugin still references old configDir skills path"
exit 1
else
echo " [PASS] Plugin does not advertise a misleading skills path"
fi
# Test 6: Verify personal test skill was created
echo "Test 6: Checking test fixtures..."
if [ -f "$OPENCODE_CONFIG_DIR/skills/personal-test/SKILL.md" ]; then
echo " [PASS] Personal test skill fixture created"
else
echo " [FAIL] Personal test skill fixture not found"
exit 1
fi
echo ""
echo "=== All plugin loading tests passed ==="
+217
View File
@@ -0,0 +1,217 @@
#!/usr/bin/env bash
# Test: Skill Priority Resolution
# Documents current OpenCode duplicate-name behavior for local and bundled
# skills. The desired local-shadowing behavior is tracked separately; this
# test keeps the integration suite honest without adding a plugin workaround.
# NOTE: These tests require OpenCode to be installed and configured
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
OPENCODE_TEST_TIMEOUT_SECONDS="${OPENCODE_TEST_TIMEOUT_SECONDS:-120}"
echo "=== Test: Skill Priority Resolution ==="
# Source setup to create isolated environment
source "$SCRIPT_DIR/setup.sh"
# Trap to cleanup on exit
trap cleanup_test_env EXIT
# Create same skill "priority-test" in all three locations with different markers
echo "Setting up priority test fixtures..."
# 1. Create in superpowers location (lowest priority)
mkdir -p "$SUPERPOWERS_SKILLS_DIR/priority-test"
cat > "$SUPERPOWERS_SKILLS_DIR/priority-test/SKILL.md" <<'EOF'
---
name: priority-test
description: Superpowers version of priority test skill
---
# Priority Test Skill (Superpowers Version)
This is the SUPERPOWERS version of the priority test skill.
PRIORITY_MARKER_SUPERPOWERS_VERSION
EOF
# 2. Create in personal location (medium priority)
mkdir -p "$OPENCODE_CONFIG_DIR/skills/priority-test"
cat > "$OPENCODE_CONFIG_DIR/skills/priority-test/SKILL.md" <<'EOF'
---
name: priority-test
description: Personal version of priority test skill
---
# Priority Test Skill (Personal Version)
This is the PERSONAL version of the priority test skill.
PRIORITY_MARKER_PERSONAL_VERSION
EOF
# 3. Create in project location (highest priority)
mkdir -p "$TEST_HOME/test-project/.opencode/skills/priority-test"
cat > "$TEST_HOME/test-project/.opencode/skills/priority-test/SKILL.md" <<'EOF'
---
name: priority-test
description: Project version of priority test skill
---
# Priority Test Skill (Project Version)
This is the PROJECT version of the priority test skill.
PRIORITY_MARKER_PROJECT_VERSION
EOF
echo " Created priority-test skill in all three locations"
# Test 1: Verify fixture setup
echo ""
echo "Test 1: Verifying test fixtures..."
if [ -f "$SUPERPOWERS_SKILLS_DIR/priority-test/SKILL.md" ]; then
echo " [PASS] Superpowers version exists"
else
echo " [FAIL] Superpowers version missing"
exit 1
fi
if [ -f "$OPENCODE_CONFIG_DIR/skills/priority-test/SKILL.md" ]; then
echo " [PASS] Personal version exists"
else
echo " [FAIL] Personal version missing"
exit 1
fi
if [ -f "$TEST_HOME/test-project/.opencode/skills/priority-test/SKILL.md" ]; then
echo " [PASS] Project version exists"
else
echo " [FAIL] Project version missing"
exit 1
fi
# Check if opencode is available for integration tests
if ! command -v opencode &> /dev/null; then
echo ""
echo " [SKIP] OpenCode not installed - skipping integration tests"
echo " To run these tests, install OpenCode: https://opencode.ai"
echo ""
echo "=== Priority fixture tests passed (integration tests skipped) ==="
exit 0
fi
run_opencode() {
local result_var="$1"
local dir="$2"
local prompt="$3"
local command_output
local exit_code
set +e
command_output=$(cd "$dir" && timeout "${OPENCODE_TEST_TIMEOUT_SECONDS}s" opencode run --print-logs --format json "$prompt" 2>&1)
exit_code=$?
set -e
if [ $exit_code -eq 124 ]; then
echo " [FAIL] OpenCode timed out after ${OPENCODE_TEST_TIMEOUT_SECONDS}s"
exit 1
fi
if [ $exit_code -ne 0 ]; then
echo " [FAIL] OpenCode returned non-zero exit code: $exit_code"
echo " Output was:"
awk 'NR <= 80 { print }' <<<"$command_output"
exit 1
fi
printf -v "$result_var" '%s' "$command_output"
}
assert_contains() {
local output="$1"
local needle="$2"
local message="$3"
if [[ "$output" == *"$needle"* ]]; then
echo " [PASS] $message"
else
echo " [FAIL] $message"
echo " Expected to find: $needle"
echo " Output was:"
awk 'NR <= 80 { print }' <<<"$output"
exit 1
fi
}
first_skill_tool_event() {
awk '/"type":"tool_use"/ && /"tool":"skill"/ { print; exit }' <<<"$1"
}
describe_priority_result() {
local output="$1"
local expected_marker="$2"
local fallback_marker="$3"
local pass_message="$4"
local known_bug_message="$5"
local loaded_skill
loaded_skill="$(first_skill_tool_event "$output")"
if [[ "$loaded_skill" == *"$expected_marker"* ]]; then
echo " [PASS] $pass_message"
elif [[ "$loaded_skill" == *"$fallback_marker"* ]]; then
echo " [INFO] $known_bug_message"
echo " [INFO] Tracked separately: OpenCode bundled skills can shadow local skills with duplicate native names"
else
echo " [FAIL] Could not verify priority marker in native skill tool output"
echo " Output was:"
awk 'NR <= 80 { print }' <<<"$output"
exit 1
fi
}
# Test 2: Document personal vs bundled superpowers priority
echo ""
echo "Test 2: Documenting personal vs superpowers priority..."
echo " Running from outside project directory..."
run_opencode output "$HOME" "Call the skill tool with name \"priority-test\". Show the exact content including any PRIORITY_MARKER text."
describe_priority_result \
"$output" \
"PRIORITY_MARKER_PERSONAL_VERSION" \
"PRIORITY_MARKER_SUPERPOWERS_VERSION" \
"Personal version loaded for duplicate native skill name" \
"Current OpenCode behavior loaded bundled superpowers version instead of personal version"
# Test 3: Document project vs bundled superpowers priority
echo ""
echo "Test 3: Documenting project vs personal/superpowers priority..."
echo " Running from project directory..."
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"priority-test\". Show the exact content including any PRIORITY_MARKER text."
describe_priority_result \
"$output" \
"PRIORITY_MARKER_PROJECT_VERSION" \
"PRIORITY_MARKER_SUPERPOWERS_VERSION" \
"Project version loaded for duplicate native skill name" \
"Current OpenCode behavior loaded bundled superpowers version instead of project version"
# Test 4: Test a non-colliding bundled superpowers skill is still available
echo ""
echo "Test 4: Testing non-colliding superpowers skill remains available..."
mkdir -p "$SUPERPOWERS_SKILLS_DIR/superpowers-only-test"
cat > "$SUPERPOWERS_SKILLS_DIR/superpowers-only-test/SKILL.md" <<'EOF'
---
name: superpowers-only-test
description: Superpowers-only priority test skill
---
# Superpowers Only Test Skill
PRIORITY_MARKER_SUPERPOWERS_ONLY_VERSION
EOF
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"superpowers-only-test\". Show the exact content including any PRIORITY_MARKER text."
assert_contains "$output" "PRIORITY_MARKER_SUPERPOWERS_ONLY_VERSION" "Non-colliding superpowers skill is still registered"
echo ""
echo "=== All priority tests passed ==="
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
# Test: Native Skill Tool Functionality
# Verifies that OpenCode's native skill tool can load personal, project,
# and bundled superpowers skills.
# NOTE: These tests require OpenCode to be installed and configured
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
OPENCODE_TEST_TIMEOUT_SECONDS="${OPENCODE_TEST_TIMEOUT_SECONDS:-120}"
echo "=== Test: Tools Functionality ==="
# Source setup to create isolated environment
source "$SCRIPT_DIR/setup.sh"
# Trap to cleanup on exit
trap cleanup_test_env EXIT
# Check if opencode is available
if ! command -v opencode &> /dev/null; then
echo " [SKIP] OpenCode not installed - skipping integration tests"
echo " To run these tests, install OpenCode: https://opencode.ai"
exit 0
fi
run_opencode() {
local result_var="$1"
local dir="$2"
local prompt="$3"
local command_output
local exit_code
set +e
command_output=$(cd "$dir" && timeout "${OPENCODE_TEST_TIMEOUT_SECONDS}s" opencode run --print-logs --format json "$prompt" 2>&1)
exit_code=$?
set -e
if [ $exit_code -eq 124 ]; then
echo " [FAIL] OpenCode timed out after ${OPENCODE_TEST_TIMEOUT_SECONDS}s"
exit 1
fi
if [ $exit_code -ne 0 ]; then
echo " [FAIL] OpenCode returned non-zero exit code: $exit_code"
echo " Output was:"
awk 'NR <= 80 { print }' <<<"$command_output"
exit 1
fi
printf -v "$result_var" '%s' "$command_output"
}
assert_contains() {
local output="$1"
local needle="$2"
local message="$3"
if [[ "$output" == *"$needle"* ]]; then
echo " [PASS] $message"
else
echo " [FAIL] $message"
echo " Expected to find: $needle"
echo " Output was:"
awk 'NR <= 80 { print }' <<<"$output"
exit 1
fi
}
# Test 1: Test personal skill loading via OpenCode's native skill tool
echo "Test 1: Testing native skill tool with a personal skill..."
echo " Running opencode with personal-test request..."
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"personal-test\". Then print the PERSONAL_SKILL_MARKER_12345 marker."
assert_contains "$output" '"tool":"skill"' "OpenCode called the native skill tool"
assert_contains "$output" "PERSONAL_SKILL_MARKER_12345" "native skill tool loaded personal-test skill content"
# Test 2: Test project skill loading
echo ""
echo "Test 2: Testing native skill tool with a project skill..."
echo " Running opencode with project-test request..."
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"project-test\". Then print the PROJECT_SKILL_MARKER_67890 marker."
assert_contains "$output" "PROJECT_SKILL_MARKER_67890" "native skill tool loaded project-test skill content"
# Test 3: Test bundled superpowers skill loading
echo ""
echo "Test 3: Testing native skill tool with a superpowers skill..."
echo " Running opencode with brainstorming skill..."
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"brainstorming\". Then tell me the loaded skill title."
assert_contains "$output" '"name":"brainstorming"' "native skill tool loaded bundled brainstorming skill"
assert_contains "$output" "Brainstorming Ideas Into Designs" "brainstorming skill content was returned"
echo ""
echo "=== All native skill tool tests passed ==="