feat: initial fork hardened for gitea.schwenk.online
Fork cursor-gitea-agent with jq event parsing, cached dependency install, and composer-2.5 as the default agent runtime. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
# Parse Gitea webhook payload and decide whether to run the Cursor agent.
|
||||
set -euo pipefail
|
||||
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "Error: jq is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
EVENT_FILE="${GITHUB_EVENT_PATH:-}"
|
||||
if [ -z "$EVENT_FILE" ] || [ ! -f "$EVENT_FILE" ]; then
|
||||
echo "Error: GITHUB_EVENT_PATH is not set or file is missing"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OUTPUT_FILE="${GITHUB_OUTPUT:?GITHUB_OUTPUT is not set}"
|
||||
|
||||
COMMENT_BODY=$(jq -r '
|
||||
if .comment?.body? then .comment.body
|
||||
elif .review?.body? then .review.body
|
||||
else empty end
|
||||
' "$EVENT_FILE")
|
||||
|
||||
if [ -z "$COMMENT_BODY" ]; then
|
||||
echo "No comment or review body in event payload — skipping."
|
||||
echo "run_cursor=false" >> "$OUTPUT_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
COMMENT_USER=$(jq -r '
|
||||
if .comment?.user?.login? then .comment.user.login
|
||||
elif .sender?.login? then .sender.login
|
||||
else "unknown" end
|
||||
' "$EVENT_FILE")
|
||||
|
||||
printf '%s' "$COMMENT_BODY" > comment.txt
|
||||
|
||||
if echo "$COMMENT_USER" | grep -qiE '^cursor$'; then
|
||||
echo "Comment from cursor bot — skipping to avoid loops."
|
||||
echo "run_cursor=false" >> "$OUTPUT_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! echo "$COMMENT_BODY" | grep -qiE '@cursor([^a-zA-Z0-9_]|$)'; then
|
||||
echo "No @cursor mention — skipping."
|
||||
echo "run_cursor=false" >> "$OUTPUT_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
jq \
|
||||
--arg event_name "${GITHUB_EVENT_NAME:-unknown}" \
|
||||
'
|
||||
{
|
||||
event_name: $event_name,
|
||||
comment: (
|
||||
if .comment then {
|
||||
body: .comment.body,
|
||||
id: .comment.id,
|
||||
user: (.comment.user.login // "unknown")
|
||||
}
|
||||
elif .review then {
|
||||
body: .review.body,
|
||||
id: .review.id,
|
||||
user: (.sender.login // "unknown")
|
||||
}
|
||||
else null end
|
||||
),
|
||||
issue: {
|
||||
number: (
|
||||
.issue.number // .pull_request.number // .number // null
|
||||
),
|
||||
title: (.issue.title // .pull_request.title // ""),
|
||||
body: (.issue.body // .pull_request.body // ""),
|
||||
state: (.issue.state // .pull_request.state // ""),
|
||||
user: (.issue.user.login // .pull_request.user.login // ""),
|
||||
html_url: (.issue.html_url // .pull_request.html_url // ""),
|
||||
is_pull_request: (
|
||||
(.pull_request != null)
|
||||
or (.issue.pull_request != null)
|
||||
or (.is_pull == true)
|
||||
)
|
||||
},
|
||||
repository: {
|
||||
name: .repository.name,
|
||||
owner: .repository.owner.login,
|
||||
full_name: .repository.full_name,
|
||||
html_url: .repository.html_url,
|
||||
default_branch: .repository.default_branch
|
||||
},
|
||||
sender: (.sender.login // "")
|
||||
}
|
||||
' "$EVENT_FILE" > context.json
|
||||
|
||||
ISSUE_NUMBER=$(jq -r '.issue.number' context.json)
|
||||
|
||||
echo "run_cursor=true" >> "$OUTPUT_FILE"
|
||||
echo "Triggered for ${COMMENT_USER} on issue/PR #${ISSUE_NUMBER} (event: ${GITHUB_EVENT_NAME:-unknown})"
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install Cursor CLI and gitea-mcp only when missing (runner cache friendly).
|
||||
set -euo pipefail
|
||||
|
||||
ensure_path() {
|
||||
if [ -d "$HOME/.local/bin" ] && [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
|
||||
echo "$HOME/.local/bin" >> "${GITHUB_PATH:?GITHUB_PATH is not set}"
|
||||
fi
|
||||
}
|
||||
|
||||
install_cursor_cli() {
|
||||
if command -v agent >/dev/null 2>&1; then
|
||||
echo "Cursor CLI already installed at $(command -v agent)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Installing Cursor CLI..."
|
||||
curl -fsSL https://cursor.com/install | bash
|
||||
ensure_path
|
||||
}
|
||||
|
||||
install_gitea_mcp() {
|
||||
local mcp_dir="/tmp/gitea-mcp"
|
||||
local mcp_bin="${mcp_dir}/gitea-mcp"
|
||||
local mcp_version="v1.3.0"
|
||||
local arch asset arch_name
|
||||
|
||||
if [ -x "$mcp_bin" ]; then
|
||||
echo "gitea-mcp already installed at $mcp_bin"
|
||||
return 0
|
||||
fi
|
||||
|
||||
arch=$(uname -m)
|
||||
case "$arch" in
|
||||
x86_64) asset="Linux_x86_64" ;;
|
||||
aarch64|arm64) asset="Linux_arm64" ;;
|
||||
*)
|
||||
echo "Unsupported architecture for gitea-mcp: $arch"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
mkdir -p "$mcp_dir"
|
||||
cd "$mcp_dir"
|
||||
|
||||
arch_name="gitea-mcp_${asset}.tar.gz"
|
||||
url="https://gitea.com/gitea/gitea-mcp/releases/download/${mcp_version}/${arch_name}"
|
||||
|
||||
echo "Downloading gitea-mcp ${mcp_version} (${asset})..."
|
||||
curl -fsSL "$url" -o gitea-mcp.tar.gz
|
||||
tar -xzf gitea-mcp.tar.gz
|
||||
chmod +x gitea-mcp
|
||||
rm -f gitea-mcp.tar.gz
|
||||
|
||||
echo "gitea-mcp ready at $mcp_bin"
|
||||
}
|
||||
|
||||
install_cursor_cli
|
||||
install_gitea_mcp
|
||||
Executable
+108
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "Error: jq is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v agent >/dev/null 2>&1; then
|
||||
echo "Error: Cursor agent CLI not found in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for file in comment.txt context.json; do
|
||||
if [ ! -f "$file" ]; then
|
||||
echo "Error: $file not found"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
REPO_FULL_NAME=$(jq -r '.repository.full_name' context.json)
|
||||
COMMENT_USER=$(jq -r '.comment.user' context.json)
|
||||
ISSUE_NUMBER=$(jq -r '.issue.number' context.json)
|
||||
|
||||
if [ "$(jq -r '.issue.is_pull_request' context.json)" = "true" ]; then
|
||||
ISSUE_TYPE="pull request"
|
||||
else
|
||||
ISSUE_TYPE="issue"
|
||||
fi
|
||||
|
||||
# Case-insensitive strip of @cursor mention and leading whitespace
|
||||
COMMENT=$(sed -E 's/.*@cursor//i' comment.txt | sed 's/^[[:space:]]*//')
|
||||
CONTEXT=$(cat context.json)
|
||||
|
||||
mkdir -p "$HOME/.cursor"
|
||||
jq -n \
|
||||
--arg cmd "/tmp/gitea-mcp/gitea-mcp" \
|
||||
--arg host "${GITEA_BASE_URL}" \
|
||||
--arg token "${GITEA_ACCESS_TOKEN}" \
|
||||
'{
|
||||
mcpServers: {
|
||||
gitea: {
|
||||
command: $cmd,
|
||||
args: ["-t", "stdio"],
|
||||
env: {
|
||||
GITEA_HOST: $host,
|
||||
GITEA_ACCESS_TOKEN: $token
|
||||
}
|
||||
}
|
||||
}
|
||||
}' > "$HOME/.cursor/mcp.json"
|
||||
|
||||
git config user.name "cursor"
|
||||
git config user.email "cursor@users.noreply.gitea.schwenk.online"
|
||||
|
||||
PROMPT="You are an autonomous software engineering agent called cursor for repository: ${REPO_FULL_NAME}
|
||||
|
||||
## CONTEXT INFORMATION
|
||||
${CONTEXT}
|
||||
|
||||
## USER REQUEST
|
||||
@${COMMENT_USER} has requested:
|
||||
${COMMENT}
|
||||
|
||||
## AVAILABLE TOOLS
|
||||
|
||||
You have full access to Gitea via MCP tools. Use them to:
|
||||
- Fetch all comments on this ${ISSUE_TYPE} to understand the full conversation history
|
||||
- If this is a PR: get the diff, changed files, and commits
|
||||
- Read files from the repository to understand the codebase
|
||||
- Create branches, make commits, and create pull requests
|
||||
- Post comments with your findings or questions
|
||||
|
||||
## YOUR INSTRUCTIONS
|
||||
|
||||
1. **Gather More Context (if needed):**
|
||||
- Let the user know you've received the request and that you now start working on it.
|
||||
- Use MCP tools to fetch all comments on ${ISSUE_TYPE} #${ISSUE_NUMBER} to understand the discussion
|
||||
- If this is a PR, use MCP tools to get the PR details, diff, and changed files
|
||||
- Read relevant files from the codebase if needed to understand the context
|
||||
|
||||
2. **Analyze the Request:**
|
||||
- Understand what the user is asking for
|
||||
- Consider the context of the ${ISSUE_TYPE} and previous discussion
|
||||
- If the request is unclear, ask for clarification via a comment
|
||||
|
||||
3. **Take Action:**
|
||||
- If implementing code: create a feature branch and open a pull request
|
||||
- If reviewing code: post a structured review in the pull request
|
||||
- If answering questions: provide helpful, accurate information
|
||||
- If the request is not feasible or safe: explain why and suggest alternatives
|
||||
- Use the MCP tool to create a Pull Request if needed
|
||||
|
||||
4. **Let the user know you've completed the request**
|
||||
- Post your response as a comment on the ${ISSUE_TYPE}
|
||||
- If the request is not feasible or safe: explain why and suggest alternatives
|
||||
|
||||
## SAFETY RULES
|
||||
|
||||
- NEVER push directly to protected branches (main, master, etc.)
|
||||
- Always use MCP tools for Gitea interactions
|
||||
- Be minimal, precise, and safe in your actions"
|
||||
|
||||
echo "Running Cursor agent for ${REPO_FULL_NAME} ${ISSUE_TYPE} #${ISSUE_NUMBER} (model: ${AI_MODEL})"
|
||||
|
||||
timeout 30m agent -p "$PROMPT" --force --model "${AI_MODEL}" --output-format=text
|
||||
|
||||
echo "Cursor agent completed."
|
||||
Reference in New Issue
Block a user