first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
name: 'Util: Claude Task Runner'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
task:
|
||||
description: 'Task description - what should Claude do?'
|
||||
required: true
|
||||
type: string
|
||||
resumeUrl:
|
||||
description: 'Optional callback URL to call with the result when the workflow completes'
|
||||
required: false
|
||||
type: string
|
||||
model:
|
||||
description: 'Claude model to use (e.g., claude-opus-4-6, claude-sonnet-4-5, claude-haiku-4-5)'
|
||||
required: false
|
||||
type: string
|
||||
default: 'claude-sonnet-4-5-20250929'
|
||||
use_raw_prompt:
|
||||
description: 'Pass the task input directly as the prompt without wrapping it with guidelines and instructions'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
max_turns:
|
||||
description: 'Maximum conversation turns before Claude stops gracefully'
|
||||
required: false
|
||||
type: number
|
||||
default: 50
|
||||
suppress_output:
|
||||
description: 'Suppress console output and job summary'
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
ref:
|
||||
description: 'Git ref (branch/tag/SHA) to check out and work on'
|
||||
required: false
|
||||
type: string
|
||||
default: 'master'
|
||||
|
||||
jobs:
|
||||
run-claude-task:
|
||||
runs-on: blacksmith-4vcpu-ubuntu-2204
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- name: Generate GitHub App Token
|
||||
id: generate_token
|
||||
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
||||
with:
|
||||
app-id: ${{ secrets.N8N_ASSISTANT_APP_ID }}
|
||||
private-key: ${{ secrets.N8N_ASSISTANT_PRIVATE_KEY }}
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
fetch-depth: 1
|
||||
token: ${{ steps.generate_token.outputs.token }}
|
||||
|
||||
- name: Configure git remote with token
|
||||
run: git remote set-url origin "https://x-access-token:${{ steps.generate_token.outputs.token }}@github.com/${{ github.repository }}.git"
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-nodejs
|
||||
with:
|
||||
build-command: ''
|
||||
|
||||
- name: Create working branch
|
||||
run: |
|
||||
BRANCH_NAME="claude/task-${{ github.run_id }}-${{ github.run_attempt }}"
|
||||
echo "BRANCH_NAME=$BRANCH_NAME" >> "$GITHUB_ENV"
|
||||
git checkout -b "$BRANCH_NAME"
|
||||
|
||||
- name: Configure git author
|
||||
run: |
|
||||
git config user.name "${{ github.actor }}"
|
||||
git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
|
||||
echo "Git author configured as: ${{ github.actor }}"
|
||||
|
||||
- name: Prepare Claude prompt
|
||||
env:
|
||||
INPUT_TASK: ${{ inputs.task }}
|
||||
USE_RAW_PROMPT: ${{ inputs.use_raw_prompt }}
|
||||
run: node .github/scripts/claude-task/prepare-claude-prompt.mjs
|
||||
|
||||
- name: Create MCP config
|
||||
run: |
|
||||
cat > /tmp/mcp-config.json << 'MCPEOF'
|
||||
{
|
||||
"mcpServers": {
|
||||
"linear": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"mcp-remote",
|
||||
"https://mcp.linear.app/sse",
|
||||
"--header",
|
||||
"Authorization:${AUTH_HEADER}"
|
||||
],
|
||||
"env": {
|
||||
"AUTH_HEADER": "Bearer MCP_LINEAR_API_KEY_PLACEHOLDER"
|
||||
}
|
||||
},
|
||||
"notion": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@notionhq/notion-mcp-server"],
|
||||
"env": {
|
||||
"OPENAPI_MCP_HEADERS": "{\"Authorization\":\"Bearer MCP_NOTION_TOKEN_PLACEHOLDER\",\"Notion-Version\":\"2025-02-19\"}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MCPEOF
|
||||
sed -i "s|MCP_LINEAR_API_KEY_PLACEHOLDER|${{ secrets.MCP_LINEAR_API_KEY }}|g" /tmp/mcp-config.json
|
||||
sed -i "s|MCP_NOTION_TOKEN_PLACEHOLDER|${{ secrets.MCP_NOTION_TOKEN }}|g" /tmp/mcp-config.json
|
||||
|
||||
- name: Run Claude
|
||||
id: claude
|
||||
continue-on-error: true
|
||||
uses: anthropics/claude-code-action@d668cc452deb931732f24c6b1bbf24d97bc0c586 # v1
|
||||
with:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
github_token: ${{ steps.generate_token.outputs.token }}
|
||||
prompt: ${{ env.CLAUDE_PROMPT }}
|
||||
show_full_output: ${{ inputs.suppress_output != true }}
|
||||
display_report: false
|
||||
settings: |
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash",
|
||||
"Read",
|
||||
"Write",
|
||||
"Edit",
|
||||
"Glob",
|
||||
"Grep",
|
||||
"WebFetch",
|
||||
"WebSearch",
|
||||
"TodoWrite",
|
||||
"Skill",
|
||||
"Task",
|
||||
"mcp__linear__*",
|
||||
"mcp__notion__*"
|
||||
]
|
||||
}
|
||||
}
|
||||
claude_args: |
|
||||
--model ${{ inputs.model }} --max-turns ${{ inputs.max_turns }} --mcp-config /tmp/mcp-config.json
|
||||
|
||||
- name: Push branch
|
||||
if: always()
|
||||
run: |
|
||||
if ! git diff --quiet "${{ inputs.ref }}" 2>/dev/null; then
|
||||
git push -u origin "$BRANCH_NAME"
|
||||
echo "::notice::Changes pushed to branch $BRANCH_NAME"
|
||||
else
|
||||
echo "::notice::No changes to push."
|
||||
fi
|
||||
|
||||
- name: Summary
|
||||
if: always()
|
||||
env:
|
||||
CLAUDE_OUTCOME: ${{ steps.claude.outcome }}
|
||||
CLAUDE_SESSION_ID: ${{ steps.claude.outputs.session_id }}
|
||||
run: |
|
||||
{
|
||||
echo "## Claude Task Runner"
|
||||
echo "**Branch:** ${BRANCH_NAME:-N/A}"
|
||||
echo "**Claude outcome:** $CLAUDE_OUTCOME"
|
||||
if [ -n "$CLAUDE_SESSION_ID" ]; then
|
||||
echo "**Session ID:** \`$CLAUDE_SESSION_ID\`"
|
||||
fi
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Call resume url
|
||||
if: always() && inputs.resumeUrl != ''
|
||||
env:
|
||||
RESUME_URL: ${{ inputs.resumeUrl }}
|
||||
EXECUTION_FILE: ${{ steps.claude.outputs.execution_file }}
|
||||
CLAUDE_OUTCOME: ${{ steps.claude.outcome }}
|
||||
CLAUDE_SESSION_ID: ${{ steps.claude.outputs.session_id }}
|
||||
run: node .github/scripts/claude-task/resume-callback.mjs
|
||||
|
||||
- name: Check final status
|
||||
if: always()
|
||||
run: |
|
||||
if [ "${{ steps.claude.outcome }}" = "failure" ]; then
|
||||
echo "::error::Claude task failed. Check the 'Run Claude' step logs for details."
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user