Skip to content
Merged
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
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
ci:
uses: agent-sh/.github/.github/workflows/ci-node.yml@main
secrets: inherit
77 changes: 77 additions & 0 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Claude Code - Automated PR Review

on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]

jobs:
claude-review:
if: >-
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'),
github.event.pull_request.author_association)

runs-on: ubuntu-latest

permissions:
contents: write
pull-requests: write
issues: write
actions: read

steps:
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0

- name: Check run count
id: check-runs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
EVENT_ACTION: ${{ github.event.action }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
WORKFLOW_FILE="claude-code-review.yml"

RUN_COUNT=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"repos/${REPO}/actions/workflows/${WORKFLOW_FILE}/runs?head_sha=${HEAD_SHA}&status=completed" \
--jq '[.workflow_runs[] | select(.event == "pull_request")] | length' || echo "")

RUN_COUNT=${RUN_COUNT:-0}
if ! echo "$RUN_COUNT" | grep -qE '^[0-9]+$'; then
echo "[WARN] Invalid RUN_COUNT value ('$RUN_COUNT') from GitHub API. Defaulting to 0."
RUN_COUNT=0
fi

RUN_COUNT=$((RUN_COUNT + 1))

echo "This is run #$RUN_COUNT for this PR (event: $EVENT_ACTION)"

if [ "$RUN_COUNT" -le 3 ]; then
echo "should_run=true" >> $GITHUB_OUTPUT
echo "[OK] Will run Claude review (run $RUN_COUNT of 3)"
else
echo "should_run=false" >> $GITHUB_OUTPUT
echo "[SKIP] Skipping Claude review (already ran 3 times)"
fi

- name: Run Claude Code Review
if: steps.check-runs.outputs.should_run == 'true'
uses: anthropics/claude-code-action@f64219702d7454cf29fe32a74104be6ed43dc637 # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
model: claude-opus-4-6
use_commit_signing: true

- name: Comment on PR (skipped)
if: steps.check-runs.outputs.should_run == 'false'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
gh pr comment "$PR_NUMBER" --body "[INFO] Claude Code review was skipped as it has already run 3 times for this PR."
57 changes: 57 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Claude Code - @mentions

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
pull_request_review:
types: [submitted]
issues:
types: [opened]

jobs:
claude-mention:
if: |
(
github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@claude') &&
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
) ||
(
github.event_name == 'pull_request_review_comment' &&
contains(github.event.comment.body, '@claude') &&
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
) ||
(
github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@claude') &&
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.review.author_association)
) ||
(
github.event_name == 'issues' &&
(contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) &&
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.issue.author_association)
)

runs-on: ubuntu-latest

permissions:
contents: write
pull-requests: write
issues: write
actions: read

steps:
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0

- name: Run Claude Code
uses: anthropics/claude-code-action@f64219702d7454cf29fe32a74104be6ed43dc637 # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
model: claude-opus-4-6
use_commit_signing: true
9 changes: 9 additions & 0 deletions scripts/pre-push-node
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
# Pre-push hook for Node.js projects
# Runs tests before allowing push

cd "$(git rev-parse --show-toplevel)" || exit 1

echo "[INFO] Running pre-push tests..."
npm test
exit $?
50 changes: 50 additions & 0 deletions scripts/setup-hooks.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/sh
# Setup git hooks for agent-sh repos
# Detects project type and installs the appropriate pre-push hook
#
# Usage: sh scripts/setup-hooks.sh

set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

# Verify we are inside a git repository
if ! git -C "$REPO_ROOT" rev-parse --git-dir >/dev/null 2>&1; then
echo "[ERROR] Not a git repository: $REPO_ROOT"
exit 1
fi

# Resolve hooks directory (handles worktrees where .git is a file)
if [ -f "$REPO_ROOT/.git" ]; then
COMMON_DIR="$(git -C "$REPO_ROOT" rev-parse --git-common-dir)"
HOOKS_DIR="$COMMON_DIR/hooks"
else
HOOKS_DIR="$REPO_ROOT/.git/hooks"
fi

mkdir -p "$HOOKS_DIR"

# Detect project type and install hook
if [ -f "$REPO_ROOT/Cargo.toml" ]; then
echo "[INFO] Detected Rust project"
if [ ! -f "$SCRIPT_DIR/pre-push-rust" ]; then
echo "[ERROR] Missing hook script: $SCRIPT_DIR/pre-push-rust"
exit 1
fi
cp "$SCRIPT_DIR/pre-push-rust" "$HOOKS_DIR/pre-push"
chmod +x "$HOOKS_DIR/pre-push"
echo "[OK] Installed pre-push hook (Rust)"
elif [ -f "$REPO_ROOT/package.json" ]; then
echo "[INFO] Detected Node.js project"
if [ ! -f "$SCRIPT_DIR/pre-push-node" ]; then
echo "[ERROR] Missing hook script: $SCRIPT_DIR/pre-push-node"
exit 1
fi
cp "$SCRIPT_DIR/pre-push-node" "$HOOKS_DIR/pre-push"
chmod +x "$HOOKS_DIR/pre-push"
echo "[OK] Installed pre-push hook (Node.js)"
else
echo "[WARN] No package.json or Cargo.toml found - skipping hook install"
exit 0
fi