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
17 changes: 17 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Description
<!-- Brief description of changes -->

## Type of Change
- [ ] `fix:` Bug fix
- [ ] `feat:` New feature
- [ ] `refactor:` Code refactoring
- [ ] `docs:` Documentation
- [ ] `test:` Tests
- [ ] `chore:` Maintenance/tooling
- [ ] `ci:` CI/CD changes

## Checklist
- [ ] Tests pass locally (`node tests/run-all.js`)
- [ ] Validation scripts pass
- [ ] Follows conventional commits format
- [ ] Updated relevant documentation
218 changes: 218 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
name: CI

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

# Prevent duplicate runs
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

# Minimal permissions
permissions:
contents: read

jobs:
test:
name: Test (${{ matrix.os }}, Node ${{ matrix.node }}, ${{ matrix.pm }})
runs-on: ${{ matrix.os }}
timeout-minutes: 10

strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: ['18.x', '20.x', '22.x']
pm: [npm, pnpm, yarn, bun]
exclude:
# Bun has limited Windows support
- os: windows-latest
pm: bun

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}

# Package manager setup
- name: Setup pnpm
if: matrix.pm == 'pnpm'
uses: pnpm/action-setup@v4
with:
version: latest

- name: Setup Bun
if: matrix.pm == 'bun'
uses: oven-sh/setup-bun@v2

# Cache configuration
- name: Get npm cache directory
if: matrix.pm == 'npm'
id: npm-cache-dir
shell: bash
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT

- name: Cache npm
if: matrix.pm == 'npm'
uses: actions/cache@v4
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-node-${{ matrix.node }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.node }}-npm-

- name: Get pnpm store directory
if: matrix.pm == 'pnpm'
id: pnpm-cache-dir
shell: bash
run: echo "dir=$(pnpm store path)" >> $GITHUB_OUTPUT

- name: Cache pnpm
if: matrix.pm == 'pnpm'
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-node-${{ matrix.node }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.node }}-pnpm-

- name: Get yarn cache directory
if: matrix.pm == 'yarn'
id: yarn-cache-dir
shell: bash
run: |
# Try Yarn Berry first, fall back to Yarn v1
if yarn config get cacheFolder >/dev/null 2>&1; then
echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
else
echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
fi

- name: Cache yarn
if: matrix.pm == 'yarn'
uses: actions/cache@v4
with:
path: ${{ steps.yarn-cache-dir.outputs.dir }}
key: ${{ runner.os }}-node-${{ matrix.node }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.node }}-yarn-

- name: Cache bun
if: matrix.pm == 'bun'
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-bun-

# Install dependencies
- name: Install dependencies
shell: bash
run: |
case "${{ matrix.pm }}" in
npm) npm ci ;;
pnpm) pnpm install ;;
# --ignore-engines required for Node 18 compat with some devDependencies (e.g., markdownlint-cli)
yarn) yarn install --ignore-engines ;;
bun) bun install ;;
*) echo "Unsupported package manager: ${{ matrix.pm }}" && exit 1 ;;
esac

# Run tests
- name: Run tests
run: node tests/run-all.js
env:
CLAUDE_CODE_PACKAGE_MANAGER: ${{ matrix.pm }}

# Upload test artifacts on failure
- name: Upload test artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-results-${{ matrix.os }}-node${{ matrix.node }}-${{ matrix.pm }}
path: |
tests/
!tests/node_modules/

validate:
name: Validate Components
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Validate agents
run: node scripts/ci/validate-agents.js
continue-on-error: false

- name: Validate hooks
run: node scripts/ci/validate-hooks.js
continue-on-error: false

- name: Validate commands
run: node scripts/ci/validate-commands.js
continue-on-error: false

- name: Validate skills
run: node scripts/ci/validate-skills.js
continue-on-error: false

- name: Validate rules
run: node scripts/ci/validate-rules.js
continue-on-error: false

security:
name: Security Scan
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Run npm audit
run: npm audit --audit-level=high
continue-on-error: true # Allows PR to proceed, but marks job as failed if vulnerabilities found

lint:
name: Lint
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Install dependencies
run: npm ci

- name: Run ESLint
run: npx eslint scripts/**/*.js tests/**/*.js

- name: Run markdownlint
run: npx markdownlint "agents/**/*.md" "skills/**/*.md" "commands/**/*.md" "rules/**/*.md"
51 changes: 51 additions & 0 deletions .github/workflows/maintenance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Scheduled Maintenance

on:
schedule:
- cron: '0 9 * * 1' # Weekly Monday 9am UTC
workflow_dispatch:

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

jobs:
dependency-check:
name: Check Dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Check for outdated packages
run: npm outdated || true

security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20.x'
- name: Run security audit
run: |
if [ -f package-lock.json ]; then
npm ci
npm audit --audit-level=high
else
echo "No package-lock.json found; skipping npm audit"
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.

stale:
name: Stale Issues/PRs
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
stale-issue-message: 'This issue is stale due to inactivity.'
stale-pr-message: 'This PR is stale due to inactivity.'
days-before-stale: 30
days-before-close: 7
47 changes: 47 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Release

on:
push:
tags: ['v*']

permissions:
contents: write

jobs:
release:
name: Create Release
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Validate version tag
run: |
if ! [[ "${{ github.ref_name }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version tag format. Expected vX.Y.Z"
exit 1
fi

- name: Generate changelog
id: changelog
run: |
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
COMMITS=$(git log --pretty=format:"- %s" HEAD)
else
COMMITS=$(git log --pretty=format:"- %s" ${PREV_TAG}..HEAD)
fi
echo "commits<<EOF" >> $GITHUB_OUTPUT
echo "$COMMITS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
body: |
## Changes
${{ steps.changelog.outputs.commits }}
generate_release_notes: false
59 changes: 59 additions & 0 deletions .github/workflows/reusable-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Reusable Release Workflow

on:
workflow_call:
inputs:
tag:
description: 'Version tag (e.g., v1.0.0)'
required: true
type: string
generate-notes:
description: 'Auto-generate release notes'
required: false
type: boolean
default: true

permissions:
contents: write

jobs:
release:
name: Create Release
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Validate version tag
run: |
if ! [[ "${{ inputs.tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version tag format. Expected vX.Y.Z"
exit 1
fi

- name: Generate changelog
id: changelog
run: |
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
COMMITS=$(git log --pretty=format:"- %s" HEAD)
else
COMMITS=$(git log --pretty=format:"- %s" ${PREV_TAG}..HEAD)
fi
# Use unique delimiter to prevent truncation if commit messages contain EOF
DELIMITER="COMMITS_END_$(date +%s)"
echo "commits<<${DELIMITER}" >> $GITHUB_OUTPUT
echo "$COMMITS" >> $GITHUB_OUTPUT
echo "${DELIMITER}" >> $GITHUB_OUTPUT

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.tag }}
body: |
## Changes
${{ steps.changelog.outputs.commits }}
generate_release_notes: ${{ inputs.generate-notes }}
Loading