Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,386 changes: 1,386 additions & 0 deletions .github/workflows/smoke-opencode.lock.yml

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions .github/workflows/smoke-opencode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
description: Smoke test workflow that validates OpenCode engine functionality twice daily
on:
schedule: every 12h
workflow_dispatch:
pull_request:
types: [labeled]
names: ["smoke"]
reaction: "eyes"
status-comment: true
permissions:
contents: read
issues: read
pull-requests: read
name: Smoke OpenCode
engine:
id: opencode
model: anthropic/claude-sonnet-4-20250514
strict: true
imports:
- shared/gh.md
- shared/reporting.md
network:
allowed:
- defaults
- github
tools:
cache-memory: true
github:
toolsets: [repos, pull_requests]
edit:
bash:
- "*"
web-fetch:
safe-outputs:
add-comment:
hide-older-comments: true
max: 2
create-issue:
expires: 2h
close-older-issues: true
labels: [automation, testing]
add-labels:
allowed: [smoke-opencode]
messages:
footer: "> ⚡ *[{workflow_name}]({run_url}) — Powered by OpenCode*"
run-started: "⚡ OpenCode initializing... [{workflow_name}]({run_url}) begins on this {event_type}..."
run-success: "🎯 [{workflow_name}]({run_url}) **MISSION COMPLETE!** OpenCode has delivered. ⚡"
run-failure: "⚠️ [{workflow_name}]({run_url}) {status}. OpenCode encountered unexpected challenges..."
timeout-minutes: 15
---

# Smoke Test: OpenCode Engine Validation

**CRITICAL EFFICIENCY REQUIREMENTS:**
- Keep ALL outputs extremely short and concise. Use single-line responses.
- NO verbose explanations or unnecessary context.
- Minimize file reading - only read what is absolutely necessary for the task.

## Test Requirements

1. **GitHub MCP Testing**: Use GitHub MCP tools to fetch details of exactly 2 merged pull requests from ${{ github.repository }} (title and number only)
2. **Web Fetch Testing**: Use the web-fetch MCP tool to fetch https://github.com and verify the response contains "GitHub" (do NOT use bash or playwright for this test - use the web-fetch MCP tool directly)
3. **File Writing Testing**: Create a test file `/tmp/gh-aw/agent/smoke-test-opencode-${{ github.run_id }}.txt` with content "Smoke test passed for OpenCode at $(date)" (create the directory if it doesn't exist)
4. **Bash Tool Testing**: Execute bash commands to verify file creation was successful (use `cat` to read the file back)
5. **Build gh-aw**: Run `GOCACHE=/tmp/go-cache GOMODCACHE=/tmp/go-mod make build` to verify the agent can successfully build the gh-aw project. If the command fails, mark this test as ❌ and report the failure.

## Output

Add a **very brief** comment (max 5-10 lines) to the current pull request with:
- ✅ or ❌ for each test result
- Overall status: PASS or FAIL

If all tests pass, use the `add_labels` safe-output tool to add the label `smoke-opencode` to the pull request.

**Important**: If no action is needed after completing your analysis, you **MUST** call the `noop` safe-output tool with a brief explanation. Failing to call any safe-output tool is the most common cause of safe-output workflow failures.

```json
{"noop": {"message": "No action needed: [brief explanation of what was analyzed and why]"}}
```
114 changes: 114 additions & 0 deletions actions/setup/sh/convert_gateway_config_opencode.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/env bash
# Convert MCP Gateway Configuration to OpenCode Format
# This script converts the gateway's standard HTTP-based MCP configuration
# to the JSON format expected by OpenCode (opencode.jsonc)
#
# OpenCode reads MCP server configuration from opencode.jsonc:
# - Project: ./opencode.jsonc (used here)
# - Global: ~/.config/opencode/opencode.json
#
# See: https://opencode.ai/docs/mcp-servers/

set -e

# Required environment variables:
# - MCP_GATEWAY_OUTPUT: Path to gateway output configuration file
# - MCP_GATEWAY_DOMAIN: Domain to use for MCP server URLs (e.g., host.docker.internal)
# - MCP_GATEWAY_PORT: Port for MCP gateway (e.g., 80)
# - GITHUB_WORKSPACE: Workspace directory for project-level config

if [ -z "$MCP_GATEWAY_OUTPUT" ]; then
echo "ERROR: MCP_GATEWAY_OUTPUT environment variable is required"
exit 1
fi

if [ ! -f "$MCP_GATEWAY_OUTPUT" ]; then
echo "ERROR: Gateway output file not found: $MCP_GATEWAY_OUTPUT"
exit 1
fi

if [ -z "$MCP_GATEWAY_DOMAIN" ]; then
echo "ERROR: MCP_GATEWAY_DOMAIN environment variable is required"
exit 1
fi

if [ -z "$MCP_GATEWAY_PORT" ]; then
echo "ERROR: MCP_GATEWAY_PORT environment variable is required"
exit 1
fi

if [ -z "$GITHUB_WORKSPACE" ]; then
echo "ERROR: GITHUB_WORKSPACE environment variable is required"
exit 1
fi

echo "Converting gateway configuration to OpenCode format..."
echo "Input: $MCP_GATEWAY_OUTPUT"
echo "Target domain: $MCP_GATEWAY_DOMAIN:$MCP_GATEWAY_PORT"

# Convert gateway output to OpenCode opencode.jsonc format
# Gateway format:
# {
# "mcpServers": {
# "server-name": {
# "type": "http",
# "url": "http://domain:port/mcp/server-name",
# "headers": {
# "Authorization": "apiKey"
# }
# }
# }
# }
#
# OpenCode format:
# {
# "mcp": {
# "server-name": {
# "type": "remote",
# "enabled": true,
# "url": "http://domain:port/mcp/server-name",
# "headers": {
# "Authorization": "apiKey"
# }
# }
# }
# }
#
# The main differences:
# 1. Top-level key is "mcp" not "mcpServers"
# 2. Server type is "remote" not "http"
# 3. Has "enabled": true field
# 4. Remove "tools" field (Copilot-specific)
# 5. URLs must use the correct domain (host.docker.internal) for container access

# Build the correct URL prefix using the configured domain and port
URL_PREFIX="http://${MCP_GATEWAY_DOMAIN}:${MCP_GATEWAY_PORT}"

OPENCODE_CONFIG_FILE="${GITHUB_WORKSPACE}/opencode.jsonc"

# Build the MCP section from gateway output
MCP_SECTION=$(jq --arg urlPrefix "$URL_PREFIX" '
.mcpServers | with_entries(
.value |= {
"type": "remote",
"enabled": true,
"url": (.url | sub("^http://[^/]+/mcp/"; $urlPrefix + "/mcp/")),
"headers": .headers
}
)
' "$MCP_GATEWAY_OUTPUT")

# Merge into existing opencode.jsonc or create new one
if [ -f "$OPENCODE_CONFIG_FILE" ]; then
echo "Merging MCP config into existing opencode.jsonc..."
jq --argjson mcpSection "$MCP_SECTION" '.mcp = (.mcp // {}) * $mcpSection' "$OPENCODE_CONFIG_FILE" > "${OPENCODE_CONFIG_FILE}.tmp"
mv "${OPENCODE_CONFIG_FILE}.tmp" "$OPENCODE_CONFIG_FILE"
else
echo "Creating new opencode.jsonc..."
jq -n --argjson mcpSection "$MCP_SECTION" '{"mcp": $mcpSection}' > "$OPENCODE_CONFIG_FILE"
fi

echo "OpenCode configuration written to $OPENCODE_CONFIG_FILE"
echo ""
echo "Converted configuration:"
cat "$OPENCODE_CONFIG_FILE"
4 changes: 4 additions & 0 deletions actions/setup/sh/start_mcp_gateway.sh
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,10 @@ case "$ENGINE_TYPE" in
echo "Using Gemini converter..."
bash /opt/gh-aw/actions/convert_gateway_config_gemini.sh
;;
opencode)
echo "Using OpenCode converter..."
bash /opt/gh-aw/actions/convert_gateway_config_opencode.sh
;;
*)
echo "No agent-specific converter found for engine: $ENGINE_TYPE"
echo "Using gateway output directly"
Expand Down
1 change: 1 addition & 0 deletions docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export default defineConfig({
{ label: 'GitHub Actions Primer', link: '/guides/github-actions-primer/' },
{ label: 'Reusing Workflows', link: '/guides/packaging-imports/' },
{ label: 'Self-Hosted Runners', link: '/guides/self-hosted-runners/' },
{ label: 'OpenCode Engine', link: '/guides/opencode/' },
{ label: 'Using MCPs', link: '/guides/mcps/' },
{ label: 'Web Search', link: '/guides/web-search/' },
],
Expand Down
Loading
Loading