はじめに
CursorやClineなどAI開発を前提としたツールが熱いですが、チーム内でCursor派、Cline派など複数の派閥があるとルールの管理が怠かったりします。(自分はRoo Codeを使うことが多いです。)
そこで今回はCursorのルールを管理する.mdcファイルを変更するPRが作成されたら.rooの配下に同じようなルールが作成されるPRを自動生成するGithub Actionsの設定を作ってみました。
設定すると以下の動きをします。
Github Actionsの設定
以下のスニペットのような.ymlを.github/workflowsに作成します。
- .cursor/**
name: Sync Cursor Rules to Roo
on:
pull_request:
paths:
- '.cursor/**/*.mdc'
types: [opened, synchronize]
jobs:
sync-cursor-rules:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Setup GitHub CLI
run: |
type -p curl >/dev/null || (sudo apt update && sudo apt install curl -y)
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
&& sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt update \
&& sudo apt install gh -y
- name: Run sync script
run: node scripts/sync-cursor-to-roo.js
- name: Check for changes
id: check-changes
run: |
if [ -n "$(git status --porcelain .roo)" ]; then
echo "changes=true" >> $GITHUB_OUTPUT
echo "changed_files<<EOF" >> $GITHUB_OUTPUT
git status --porcelain .roo >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
else
echo "changes=false" >> $GITHUB_OUTPUT
fi
- name: Create PR for .roo changes
if: steps.check-changes.outputs.changes == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Get current PR info
PR_NUMBER=${{ github.event.number }}
PR_BRANCH=${{ github.head_ref }}
BASE_BRANCH=${{ github.base_ref }}
# Create a new branch for .roo changes with timestamp to ensure uniqueness
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
ROO_BRANCH="sync-roo-from-pr-${PR_NUMBER}-${TIMESTAMP}"
# Configure git
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
# Delete existing branch if it exists (both locally and remotely)
git branch -D "sync-roo-from-pr-${PR_NUMBER}" 2>/dev/null || true
git push origin --delete "sync-roo-from-pr-${PR_NUMBER}" 2>/dev/null || true
# Create and switch to new branch
git checkout -b "${ROO_BRANCH}"
# Add and commit .roo changes
git add .roo
git commit -m "Auto-sync: Update .roo files from .cursor changes in PR #${PR_NUMBER}
This PR automatically syncs .cursor rule changes to .roo directory.
Source PR: #${PR_NUMBER}
Changed files:
${{ steps.check-changes.outputs.changed_files }}"
# Push the new branch (use force push to handle any conflicts)
git push --force-with-lease origin "${ROO_BRANCH}"
# Create PR using GitHub CLI
gh pr create \
--title "🔄 Auto-sync .roo from .cursor changes (PR #${PR_NUMBER})" \
--body "This PR automatically syncs .cursor rule changes to .roo directory.
## Source
- **Source PR**: #${PR_NUMBER}
- **Source Branch**: \`${PR_BRANCH}\`
## Changes
- Converted .mdc files to .md files
- Removed frontmatter from rule files
- Updated .roo directory structure
## Files Changed
\`\`\`
${{ steps.check-changes.outputs.changed_files }}
\`\`\`
## Auto-generated
This PR was automatically created by GitHub Actions when .cursor files were modified." \
--base "${PR_BRANCH}" \
--head "${ROO_BRANCH}" \
--label "auto-sync" \
--label "roo-sync"
流れとしては以下のような感じです。
-
トリガー
- 対象ファイル:.cursor 配下の .mdc ファイル
- 対象イベント:Pull Requestの作成 (opened) または更新 (synchronize)
-
環境の設定
- Node.jsのセットアップ
- 対象リポジトリをクローン
- GitHub CLI のインストール
-
RooCode用のPR作成
- .cursor → .roo への同期スクリプト実行(詳細は後述)
- .roo ディレクトリに差分があるか確認
- 差分があればPRを自動作成
.cursor → .roo のルールファイル作成スクリプト
Github Actionsで実行されるコードは以下になります。
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
function processFile(filePath) {
console.log(`Processing: ${filePath}`);
// Read the .mdc file
const content = fs.readFileSync(filePath, 'utf8');
// Remove frontmatter (from first --- to second ---)
const lines = content.split('\n');
let startIndex = -1;
let endIndex = -1;
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim() === '---') {
if (startIndex === -1) {
startIndex = i;
} else {
endIndex = i;
break;
}
}
}
let processedContent;
if (startIndex !== -1 && endIndex !== -1) {
// Remove frontmatter
processedContent = lines.slice(endIndex + 1).join('\n');
} else {
// No frontmatter found, use original content
processedContent = content;
}
// Determine output path
const relativePath = path.relative('.cursor', filePath);
// Convert 'rules' directory to 'rules-code' if the path starts with 'rules/'
let outputRelativePath = relativePath;
if (outputRelativePath.startsWith('rules/')) {
outputRelativePath = 'rules-code/' + outputRelativePath.substring('rules/'.length);
}
const outputPath = path.join('.roo', outputRelativePath.replace(/\.mdc$/, '.md'));
// Create output directory if it doesn't exist
const outputDir = path.dirname(outputPath);
fs.mkdirSync(outputDir, { recursive: true });
// Write processed content
fs.writeFileSync(outputPath, processedContent);
console.log(`Created: ${outputPath}`);
}
function findMdcFiles(dir) {
const files = [];
const items = fs.readdirSync(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
files.push(...findMdcFiles(fullPath));
} else if (item.endsWith('.mdc')) {
files.push(fullPath);
}
}
return files;
}
// Main execution
console.log('Starting sync from .cursor to .roo...');
if (fs.existsSync('.cursor')) {
const mdcFiles = findMdcFiles('.cursor');
console.log(`Found ${mdcFiles.length} .mdc files`);
for (const file of mdcFiles) {
processFile(file);
}
console.log('Sync completed successfully');
} else {
console.log('No .cursor directory found');
}
流れとしては以下のような感じです。
- .mdc → .md に変換
- frontmatter(YAML形式のメタデータ)を削除
- rules/ → rules-code/ にディレクトリ名を変換
- 変換後のファイルを .roo/ に保存
おわりに
一旦作ってRoo Codeのルールファイルも自動でメンテナンスされるようになりました。
とはいえ、すべての変更をRoo CodeのCodeモードに対応しているrules-codeディレクトリに突っ込んでしまっているなど、コードの改善の余地はあるので、今後運用しながらCursorを使う人も、Cline(Roo Cline)を使う人も常に快適にAI活用できるようブラッシュアップしていきたいと思います。
また今回のyml, jsファイルはどちらも完全にAIが作成してくれていて、作成時間は30m未満でした。「自動化系の実装も速攻で実現できるようになって楽だな〜」と思ったので、フットワーク軽く改善~検証をしていきたいですね。