392 lines
9.9 KiB
Bash
Executable File
392 lines
9.9 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# init-skill.sh - Scaffold a new skill with proper structure
|
|
#
|
|
# Usage: ./init-skill.sh <skill-name> [options]
|
|
#
|
|
# Options:
|
|
# --local Create in current project (.opencode/skills/) instead of global
|
|
# --with-scripts Include scripts/ directory
|
|
# --with-refs Include references/ directory
|
|
# --with-assets Include assets/ directory
|
|
# --with-tests Include evals/ directory for test cases
|
|
# --full Include all optional directories
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Get script directory
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
SKILL_BUILDER_DIR="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# Parse arguments
|
|
SKILL_NAME=""
|
|
LOCAL=false
|
|
WITH_SCRIPTS=false
|
|
WITH_REFS=false
|
|
WITH_ASSETS=false
|
|
WITH_TESTS=false
|
|
|
|
usage() {
|
|
echo "Usage: $0 <skill-name> [options]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --local Create in current project (.opencode/skills/)"
|
|
echo " --with-scripts Include scripts/ directory"
|
|
echo " --with-refs Include references/ directory"
|
|
echo " --with-assets Include assets/ directory"
|
|
echo " --with-tests Include evals/ directory for test cases"
|
|
echo " --full Include all optional directories"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " $0 my-skill"
|
|
echo " $0 my-skill --full"
|
|
echo " $0 my-skill --local --with-scripts"
|
|
exit 1
|
|
}
|
|
|
|
# Validate skill name
|
|
validate_name() {
|
|
local name="$1"
|
|
|
|
if [[ -z "$name" ]]; then
|
|
echo -e "${RED}Error: Skill name is required${NC}"
|
|
usage
|
|
fi
|
|
|
|
if [[ ! "$name" =~ ^[a-z0-9-]+$ ]]; then
|
|
echo -e "${RED}Error: Skill name must be lowercase alphanumeric with hyphens only${NC}"
|
|
echo " Valid: my-skill, docker-helper, test-runner"
|
|
echo " Invalid: My Skill, docker_helper, testRunner"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ${#name} -lt 1 ]]; then
|
|
echo -e "${RED}Error: Skill name cannot be empty${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ${#name} -gt 64 ]]; then
|
|
echo -e "${RED}Error: Skill name must be under 64 characters${NC}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Parse command line arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--local)
|
|
LOCAL=true
|
|
shift
|
|
;;
|
|
--with-scripts)
|
|
WITH_SCRIPTS=true
|
|
shift
|
|
;;
|
|
--with-refs)
|
|
WITH_REFS=true
|
|
shift
|
|
;;
|
|
--with-assets)
|
|
WITH_ASSETS=true
|
|
shift
|
|
;;
|
|
--with-tests)
|
|
WITH_TESTS=true
|
|
shift
|
|
;;
|
|
--full)
|
|
WITH_SCRIPTS=true
|
|
WITH_REFS=true
|
|
WITH_ASSETS=true
|
|
WITH_TESTS=true
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
;;
|
|
-*)
|
|
echo -e "${RED}Error: Unknown option $1${NC}"
|
|
usage
|
|
;;
|
|
*)
|
|
if [[ -z "$SKILL_NAME" ]]; then
|
|
SKILL_NAME="$1"
|
|
else
|
|
echo -e "${RED}Error: Multiple skill names provided${NC}"
|
|
usage
|
|
fi
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Validate skill name
|
|
validate_name "$SKILL_NAME"
|
|
|
|
# Determine target directory
|
|
if [[ "$LOCAL" == true ]]; then
|
|
# Check if we're in a git repository
|
|
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
|
echo -e "${RED}Error: --local requires being in a git repository${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
TARGET_DIR=".opencode/skills/$SKILL_NAME"
|
|
|
|
# Check for AGENTS.md in project
|
|
if [[ -f "AGENTS.md" ]]; then
|
|
echo -e "${GREEN}✓ Found AGENTS.md in project root${NC}"
|
|
else
|
|
echo -e "${YELLOW}⚠ No AGENTS.md found in project root${NC}"
|
|
echo " Consider creating one for project-specific rules"
|
|
fi
|
|
else
|
|
TARGET_DIR="$HOME/.config/opencode/skills/$SKILL_NAME"
|
|
fi
|
|
|
|
# Check if skill already exists
|
|
if [[ -d "$TARGET_DIR" ]]; then
|
|
echo -e "${RED}Error: Skill already exists at $TARGET_DIR${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo -e "${GREEN}Creating skill: $SKILL_NAME${NC}"
|
|
echo " Location: $TARGET_DIR"
|
|
echo ""
|
|
|
|
# Create skill directory
|
|
mkdir -p "$TARGET_DIR"
|
|
|
|
# Create SKILL.md
|
|
cat > "$TARGET_DIR/SKILL.md" << 'SKILL_TEMPLATE'
|
|
---
|
|
name: SKILL_NAME_PLACEHOLDER
|
|
description: This skill should be used when the user asks to "DESCRIPTION_HERE". Add specific trigger phrases that would activate this skill.
|
|
license: MIT
|
|
compatibility: opencode
|
|
metadata:
|
|
category: general
|
|
version: "1.0.0"
|
|
---
|
|
|
|
# SKILL_NAME_PLACEHOLDER
|
|
|
|
Brief description of what this skill does and its purpose.
|
|
|
|
## What This Skill Provides
|
|
|
|
1. **Feature 1** - Brief description
|
|
2. **Feature 2** - Brief description
|
|
3. **Feature 3** - Brief description
|
|
|
|
## Quick Start
|
|
|
|
Basic usage example:
|
|
|
|
```bash
|
|
# Example command
|
|
some-tool --option value
|
|
```
|
|
|
|
## Common Tasks
|
|
|
|
### Task 1: Description
|
|
|
|
Step-by-step instructions:
|
|
|
|
1. First step
|
|
2. Second step
|
|
3. Third step
|
|
|
|
### Task 2: Description
|
|
|
|
Step-by-step instructions:
|
|
|
|
1. First step
|
|
2. Second step
|
|
|
|
## Important Notes
|
|
|
|
- Keep this section brief
|
|
- Use bullet points for clarity
|
|
- Reference supporting files if available
|
|
|
|
## Resources
|
|
|
|
SKILL_TEMPLATE
|
|
|
|
# Add resource section if directories were created
|
|
if [[ "$WITH_REFS" == true ]]; then
|
|
cat >> "$TARGET_DIR/SKILL.md" << 'REF_SECTION'
|
|
|
|
### Reference Files
|
|
|
|
- `references/detailed-guide.md` - Detailed documentation
|
|
|
|
REF_SECTION
|
|
fi
|
|
|
|
if [[ "$WITH_SCRIPTS" == true ]]; then
|
|
cat >> "$TARGET_DIR/SKILL.md" << 'SCRIPT_SECTION'
|
|
|
|
### Scripts
|
|
|
|
- `scripts/helper.sh` - Utility script
|
|
|
|
SCRIPT_SECTION
|
|
fi
|
|
|
|
if [[ "$WITH_ASSETS" == true ]]; then
|
|
cat >> "$TARGET_DIR/SKILL.md" << 'ASSET_SECTION'
|
|
|
|
### Assets
|
|
|
|
- `assets/template.txt` - Template file
|
|
|
|
ASSET_SECTION
|
|
fi
|
|
|
|
# Replace placeholder with actual skill name
|
|
sed -i "s/SKILL_NAME_PLACEHOLDER/$SKILL_NAME/g" "$TARGET_DIR/SKILL.md"
|
|
|
|
# Create optional directories
|
|
if [[ "$WITH_SCRIPTS" == true ]]; then
|
|
mkdir -p "$TARGET_DIR/scripts"
|
|
|
|
# Create example script
|
|
cat > "$TARGET_DIR/scripts/helper.sh" << 'SCRIPT_EXAMPLE'
|
|
#!/bin/bash
|
|
#
|
|
# Helper script for SKILL_NAME_PLACEHOLDER
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
echo "Helper script for SKILL_NAME_PLACEHOLDER"
|
|
echo "Modify this script for your needs"
|
|
SCRIPT_EXAMPLE
|
|
|
|
sed -i "s/SKILL_NAME_PLACEHOLDER/$SKILL_NAME/g" "$TARGET_DIR/scripts/helper.sh"
|
|
chmod +x "$TARGET_DIR/scripts/helper.sh"
|
|
|
|
echo -e "${GREEN} ✓ Created scripts/ directory${NC}"
|
|
fi
|
|
|
|
if [[ "$WITH_REFS" == true ]]; then
|
|
mkdir -p "$TARGET_DIR/references"
|
|
|
|
# Create example reference
|
|
cat > "$TARGET_DIR/references/detailed-guide.md" << 'REF_EXAMPLE'
|
|
# Detailed Guide for SKILL_NAME_PLACEHOLDER
|
|
|
|
This file contains detailed documentation that can be referenced on-demand.
|
|
|
|
## Advanced Usage
|
|
|
|
Detailed instructions go here...
|
|
|
|
## Configuration
|
|
|
|
Configuration options and examples...
|
|
|
|
## Troubleshooting
|
|
|
|
Common issues and solutions...
|
|
REF_EXAMPLE
|
|
|
|
sed -i "s/SKILL_NAME_PLACEHOLDER/$SKILL_NAME/g" "$TARGET_DIR/references/detailed-guide.md"
|
|
|
|
echo -e "${GREEN} ✓ Created references/ directory${NC}"
|
|
fi
|
|
|
|
if [[ "$WITH_ASSETS" == true ]]; then
|
|
mkdir -p "$TARGET_DIR/assets"
|
|
|
|
# Create example asset
|
|
cat > "$TARGET_DIR/assets/template.txt" << 'ASSET_EXAMPLE'
|
|
# Template file for SKILL_NAME_PLACEHOLDER
|
|
|
|
This is a template file that can be used as a starting point.
|
|
Modify it according to your needs.
|
|
ASSET_EXAMPLE
|
|
|
|
sed -i "s/SKILL_NAME_PLACEHOLDER/$SKILL_NAME/g" "$TARGET_DIR/assets/template.txt"
|
|
|
|
echo -e "${GREEN} ✓ Created assets/ directory${NC}"
|
|
fi
|
|
|
|
if [[ "$WITH_TESTS" == true ]]; then
|
|
mkdir -p "$TARGET_DIR/evals"
|
|
|
|
# Create template evals.json
|
|
cat > "$TARGET_DIR/evals/evals.json" << 'EVALS_TEMPLATE'
|
|
{
|
|
"skill_name": "SKILL_NAME_PLACEHOLDER",
|
|
"evals": [
|
|
{
|
|
"id": 1,
|
|
"name": "common-case",
|
|
"prompt": "Typical user request with realistic context, file paths, and specific details. This represents the most common way users will ask for help.",
|
|
"expected_output": "Description of what the skill should produce for this request",
|
|
"assertions": [
|
|
"Check that output contains specific expected content",
|
|
"Verify file is created at expected location (if applicable)"
|
|
]
|
|
},
|
|
{
|
|
"id": 2,
|
|
"name": "edge-case",
|
|
"prompt": "Unusual or tricky scenario that tests edge cases, error handling, or complex requirements. Include something that might break the skill.",
|
|
"expected_output": "Description of expected behavior for this edge case",
|
|
"assertions": [
|
|
"Verify edge case is handled appropriately",
|
|
"Check for graceful error handling if applicable"
|
|
]
|
|
},
|
|
{
|
|
"id": 3,
|
|
"name": "varied-phrasing",
|
|
"prompt": "Same intent as the common case but expressed with different words, casual language, or alternative phrasing. Tests skill robustness to language variation.",
|
|
"expected_output": "Same expected output as common case",
|
|
"assertions": [
|
|
"Output should match common case results",
|
|
"Skill triggers correctly with different phrasing"
|
|
]
|
|
}
|
|
]
|
|
}
|
|
EVALS_TEMPLATE
|
|
|
|
sed -i "s/SKILL_NAME_PLACEHOLDER/$SKILL_NAME/g" "$TARGET_DIR/evals/evals.json"
|
|
|
|
echo -e "${GREEN} ✓ Created evals/ directory with template evals.json${NC}"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}✓ Skill '$SKILL_NAME' created successfully!${NC}"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " 1. Edit $TARGET_DIR/SKILL.md"
|
|
echo " 2. Fill in the description with specific trigger phrases"
|
|
echo " 3. Add your skill content"
|
|
if [[ "$WITH_REFS" == true ]]; then
|
|
echo " 4. Add detailed content to references/ files"
|
|
fi
|
|
if [[ "$WITH_SCRIPTS" == true ]]; then
|
|
echo " 5. Implement scripts in scripts/ directory"
|
|
fi
|
|
if [[ "$WITH_TESTS" == true ]]; then
|
|
echo " 6. Customize test cases in evals/evals.json"
|
|
echo " 7. Run tests: ${SKILL_BUILDER_DIR}/scripts/run-tests.sh $TARGET_DIR"
|
|
fi
|
|
echo ""
|
|
echo "Validate your skill:"
|
|
echo " ${SKILL_BUILDER_DIR}/scripts/validate-skill.sh $TARGET_DIR"
|