added opencode

This commit is contained in:
Bryan Ramos 2026-04-12 23:05:31 -04:00
parent 54acfec834
commit 254d72cfd4
8 changed files with 315 additions and 4 deletions

View file

@ -28,6 +28,10 @@ CLAUDE_AGENTS_DIR="$CLAUDE_DIR/agents"
CODEX_DIR="$SCRIPT_DIR/codex"
CODEX_AGENTS_DIR="$CODEX_DIR/agents"
OPENCODE_DIR="$SCRIPT_DIR/opencode"
OPENCODE_AGENTS_DIR="$OPENCODE_DIR/agents"
OPENCODE_BASE_CONFIG="$OPENCODE_DIR/config.json"
# ---------------------------------------------------------------------------
# Template variable values per target (KEY=VALUE pairs)
# ---------------------------------------------------------------------------
@ -43,6 +47,12 @@ CODEX_VARS=(
"SEARCH_TOOLS=Search the codebase"
)
OPENCODE_VARS=(
"PLANS_DIR=plans"
"WEB_SEARCH=via web search"
"SEARCH_TOOLS=Search the codebase"
)
# ---------------------------------------------------------------------------
# extract_body — extracts everything after the second --- (YAML frontmatter)
# ---------------------------------------------------------------------------
@ -249,6 +259,101 @@ map_portable_tool_to_claude() {
esac
}
# ---------------------------------------------------------------------------
# map_model_to_opencode — all models map to the single local model
# ---------------------------------------------------------------------------
map_model_to_opencode() {
echo "llama.cpp/qwen3-coder:a3b"
}
# ---------------------------------------------------------------------------
# map_effort_to_temperature — maps effort to temperature float
# ---------------------------------------------------------------------------
map_effort_to_temperature() {
local effort="$1"
case "$effort" in
max) echo "0.1" ;;
high) echo "0.2" ;;
medium) echo "0.3" ;;
low) echo "0.5" ;;
*) echo "0.3" ;;
esac
}
# ---------------------------------------------------------------------------
# map_permission_mode_to_opencode_mode — maps permission mode to agent mode
# ---------------------------------------------------------------------------
map_permission_mode_to_opencode_mode() {
local permission_mode="$1"
case "$permission_mode" in
plan) echo "subagent" ;;
*) echo "primary" ;;
esac
}
# ---------------------------------------------------------------------------
# generate_opencode_permission_block — emits YAML permission block for agent
# $1 = tools (comma-separated Claude tool names)
# $2 = disallowed_tools (comma-separated Claude tool names)
# $3 = permission_mode (plan/acceptEdits/"")
# ---------------------------------------------------------------------------
generate_opencode_permission_block() {
local tools="$1"
local disallowed_tools="$2"
local permission_mode="$3"
local edit_perm="deny"
local bash_perm="deny"
local webfetch_perm="deny"
if [ "$permission_mode" = "plan" ]; then
# Plan-mode agents: read-only, no edits, no bash
edit_perm="deny"
bash_perm="deny"
# Researchers/reviewers still need web access
if echo "$tools" | grep -qE '\bWebFetch\b|\bWebSearch\b'; then
webfetch_perm="allow"
fi
else
# Check edit permission
if echo "$tools" | grep -qE '\bWrite\b|\bEdit\b'; then
edit_perm="allow"
fi
if echo "$disallowed_tools" | grep -qE '\bWrite\b|\bEdit\b'; then
edit_perm="deny"
fi
# Check bash permission
if echo "$tools" | grep -q '\bBash\b'; then
bash_perm="ask"
fi
if echo "$disallowed_tools" | grep -q '\bBash\b'; then
bash_perm="deny"
fi
# Check web permission
if echo "$tools" | grep -qE '\bWebFetch\b|\bWebSearch\b'; then
webfetch_perm="allow"
fi
fi
echo "permission:"
echo " edit: ${edit_perm}"
if [ "$bash_perm" = "ask" ]; then
echo " bash:"
echo " \"*\": ask"
echo " \"git status\": allow"
echo " \"git diff *\": allow"
echo " \"git log *\": allow"
elif [ "$bash_perm" = "deny" ]; then
echo " bash:"
echo " \"*\": deny"
fi
echo " webfetch: ${webfetch_perm}"
}
# ---------------------------------------------------------------------------
# json_escape — escapes a string for JSON string literal output
# ---------------------------------------------------------------------------
@ -712,12 +817,134 @@ TOML
echo "Generated: $CODEX_DIR/config.toml"
}
# ---------------------------------------------------------------------------
# generate_opencode — produces opencode/ output directory
# ---------------------------------------------------------------------------
generate_opencode() {
echo ""
echo "=== Generating OpenCode output ==="
# Clean generated outputs only (preserve user-authored config.json)
rm -rf "$OPENCODE_AGENTS_DIR"
rm -f "$OPENCODE_DIR/AGENTS.md"
rm -f "$OPENCODE_DIR/opencode.json"
mkdir -p "$OPENCODE_AGENTS_DIR"
# Symlink skills
if [ -L "$OPENCODE_DIR/skills" ]; then
rm "$OPENCODE_DIR/skills"
fi
ln -s ../skills "$OPENCODE_DIR/skills"
echo "Symlinked: $OPENCODE_DIR/skills -> ../skills"
# Generate agent .md files with OpenCode frontmatter
local agent_id
while IFS= read -r agent_id; do
[ -n "$agent_id" ] || continue
local name description model effort permission_mode
local src_file dst_file body expanded_body
local max_turns tools_csv disallowed_tools_csv
local opencode_model opencode_temperature opencode_mode opencode_steps
name="$(yq -r ".agents.items.${agent_id}.name" "$TEAM_YAML")"
description="$(yq -r ".agents.items.${agent_id}.description" "$TEAM_YAML")"
model="$(yq -r ".agents.items.${agent_id}.model" "$TEAM_YAML")"
effort="$(yq -r ".agents.items.${agent_id}.effort // \"\"" "$TEAM_YAML")"
permission_mode="$(yq -r ".agents.items.${agent_id}.permission_mode // \"\"" "$TEAM_YAML")"
tools_csv="$(yq -r ".agents.items.${agent_id}.tools[]" "$TEAM_YAML" | csv_from_yaml_array)"
disallowed_tools_csv="$(yq -r ".agents.items.${agent_id}.disallowed_tools // [] | .[]" "$TEAM_YAML" | csv_from_yaml_array)"
max_turns="$(yq -r ".agents.items.${agent_id}.max_turns // \"\"" "$TEAM_YAML")"
src_file="$SCRIPT_DIR/$(yq -r ".agents.items.${agent_id}.instruction_file" "$TEAM_YAML")"
dst_file="$OPENCODE_AGENTS_DIR/${name}.md"
body="$(extract_body "$src_file")"
expanded_body="$(expand_body "$body" "${OPENCODE_VARS[@]}")"
# Map to OpenCode equivalents
opencode_model="$(map_model_to_opencode "$model")"
opencode_temperature="$(map_effort_to_temperature "${effort:-medium}")"
opencode_mode="$(map_permission_mode_to_opencode_mode "$permission_mode")"
opencode_steps="${max_turns:-25}"
{
echo "---"
echo "description: '$(yaml_escape_single_quoted "$description")'"
echo "mode: ${opencode_mode}"
echo "model: ${opencode_model}"
echo "temperature: ${opencode_temperature}"
echo "steps: ${opencode_steps}"
generate_opencode_permission_block "$tools_csv" "$disallowed_tools_csv" "$permission_mode"
echo "---"
echo ""
echo "$expanded_body"
} > "$dst_file"
echo "Generated: $dst_file"
done < <(yq -r '.agents.order[]' "$TEAM_YAML")
# Generate AGENTS.md — concatenate TEAM-ordered rules for opencode target
echo ""
echo "Generating opencode/AGENTS.md..."
{
echo "# Agent Team Instructions"
echo ""
echo "Agent-team specific protocols live in skills (orchestrate, conventions, worker-protocol, qa-checklist, message-schema)."
local rule_id rules_file
while IFS= read -r rule_id; do
[ -n "$rule_id" ] || continue
yq -r ".rules.items.${rule_id}.applies_to[]" "$TEAM_YAML" | grep -qx "opencode" || continue
rules_file="$SCRIPT_DIR/$(yq -r ".rules.items.${rule_id}.source_file" "$TEAM_YAML")"
echo ""
cat "$rules_file"
done < <(yq -r '.rules.order[]' "$TEAM_YAML")
} > "$OPENCODE_DIR/AGENTS.md"
echo "Generated: $OPENCODE_DIR/AGENTS.md"
# Generate merged opencode.json — base config + generated overlay
echo ""
echo "Generating opencode/opencode.json..."
if [ ! -f "$OPENCODE_BASE_CONFIG" ]; then
echo "Error: missing base config at $OPENCODE_BASE_CONFIG"
exit 1
fi
# Build the generated overlay with global permissions from SETTINGS.yaml
local overlay_json
overlay_json="$(cat <<'OVERLAY'
{
"permission": {
"edit": "ask",
"bash": {
"*": "ask"
},
"webfetch": "allow",
"skill": {
"*": "allow"
}
},
"compaction": {
"auto": true,
"prune": true
},
"snapshot": true
}
OVERLAY
)"
jq -s '.[0] * .[1]' "$OPENCODE_BASE_CONFIG" <(echo "$overlay_json") > "$OPENCODE_DIR/opencode.json"
echo "Generated: $OPENCODE_DIR/opencode.json"
}
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
prepare_settings_json
generate_claude
generate_codex
generate_opencode
echo ""
echo "Done."