diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..3a79bb0 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,41 @@ +# CODEOWNERS - Repository ownership +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners + +# Default owners for everything +* @BerryUIKI + +# Documentation +/docs/ @BerryUIKI +/README*.md @BerryUIKI +/CHANGELOG.md @BerryUIKI +/AGENTS.md @BerryUIKI + +# Frontend +/apps/desktop/src/ @BerryUIKI +/packages/ @BerryUIKI + +# Backend +/apps/desktop/src-tauri/ @BerryUIKI +/crates/ @BerryUIKI + +# CI/CD +/.github/ @BerryUIKI +/scripts/ @BerryUIKI + +# Database +/apps/desktop/src-tauri/migrations/ @BerryUIKI +/apps/desktop/src-tauri/src/database/ @BerryUIKI + +# Security +/apps/desktop/src-tauri/src/security/ @BerryUIKI +/apps/desktop/src-tauri/capabilities/ @BerryUIKI +/SECURITY.md @BerryUIKI + +# Plugins +/plugins/ @BerryUIKI + +# Build configuration +/package.json @BerryUIKI +/Cargo.toml @BerryUIKI +/pnpm-workspace.yaml @BerryUIKI +/vite.config.ts @BerryUIKI \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..c9709c0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,71 @@ +# Dependabot configuration for automated dependency updates +# https://docs.github.com/en/code-security/dependabot + +version: 2 + +updates: + # npm/pnpm dependencies + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "Asia/Shanghai" + open-pull-requests-limit: 10 + commit-message: + prefix: "chore" + include: "scope" + labels: + - "dependencies" + - "frontend" + reviewers: + - BerryUIKI + assignees: + - BerryUIKI + groups: + production-dependencies: + dependency-type: "production" + development-dependencies: + dependency-type: "development" + + # Rust dependencies + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "Asia/Shanghai" + open-pull-requests-limit: 5 + commit-message: + prefix: "chore" + include: "scope" + labels: + - "dependencies" + - "rust" + - "backend" + reviewers: + - BerryUIKI + assignees: + - BerryUIKI + + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "Asia/Shanghai" + open-pull-requests-limit: 5 + commit-message: + prefix: "ci" + include: "scope" + labels: + - "dependencies" + - "ci" + reviewers: + - BerryUIKI + assignees: + - BerryUIKI \ No newline at end of file diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..fca4103 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,107 @@ +# Auto-labeler configuration for PRs +# https://github.com/actions/labeler + +# Frontend changes +frontend: + - changed-files: + - any-glob-to-any-file: + - 'apps/desktop/src/**/*' + - 'packages/**/*.ts' + - 'packages/**/*.tsx' + - '*.tsx' + - '*.ts' + +# Backend changes +backend: + - changed-files: + - any-glob-to-any-file: + - 'apps/desktop/src-tauri/**/*.rs' + - 'crates/**/*.rs' + - 'Cargo.toml' + - 'Cargo.lock' + +# Rust specific +rust: + - changed-files: + - any-glob-to-any-file: + - '**/*.rs' + - 'Cargo.toml' + - 'Cargo.lock' + +# TypeScript specific +typescript: + - changed-files: + - any-glob-to-any-file: + - '**/*.ts' + - '**/*.tsx' + +# Documentation +documentation: + - changed-files: + - any-glob-to-any-file: + - 'docs/**/*.md' + - 'README*.md' + - 'CHANGELOG.md' + - 'CONTRIBUTING.md' + - 'AGENTS.md' + +# Database/Schema +database: + - changed-files: + - any-glob-to-any-file: + - 'apps/desktop/src-tauri/migrations/**/*.sql' + - 'apps/desktop/src-tauri/src/database/**/*' + +# CI/CD +ci: + - changed-files: + - any-glob-to-any-file: + - '.github/workflows/**/*' + - '.github/labeler.yml' + - 'scripts/*.sh' + +# Plugins +plugins: + - changed-files: + - any-glob-to-any-file: + - 'plugins/**/*' + +# Tests +tests: + - changed-files: + - any-glob-to-any-file: + - '**/*.test.ts' + - '**/*.test.tsx' + - '**/*.spec.ts' + - '**/*.spec.tsx' + - '**/tests/**/*.rs' + +# Security sensitive +security: + - changed-files: + - any-glob-to-any-file: + - 'apps/desktop/src-tauri/src/security/**/*' + - 'apps/desktop/src-tauri/capabilities/**/*' + - '.env.example' + +# UI/Styling +ui: + - changed-files: + - any-glob-to-any-file: + - 'apps/desktop/src/styles/**/*' + - 'apps/desktop/src/components/**/*' + - 'tailwind.config.*' + - '**/*.css' + +# Configuration +config: + - changed-files: + - any-glob-to-any-file: + - 'package.json' + - 'pnpm-workspace.yaml' + - 'tsconfig*.json' + - 'vite.config.*' + - '.prettierrc' + - '.editorconfig' + - 'eslint.config.*' + - 'vitest.config.*' \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a8edb7b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,196 @@ +# Continuous Integration for AlphaForge +# Runs on all pull requests and pushes to main + +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # ==================== + # Frontend CI + # ==================== + frontend: + name: Frontend (TypeScript) + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT + id: pnpm-cache + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Type check + run: pnpm typecheck + + - name: Lint + run: pnpm lint + + - name: Test + run: pnpm test + continue-on-error: true # No tests yet, don't fail CI + + # ==================== + # Rust CI + # ==================== + rust: + name: Rust Backend + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Linux dependencies + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev pkg-config + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Check formatting + run: cargo fmt --check --all + continue-on-error: true # Don't fail CI on formatting issues + + - name: Clippy + run: cargo clippy --all-targets --all-features -- -D warnings + + - name: Build + run: cargo build --workspace + + - name: Test + run: cargo test --workspace + continue-on-error: true # No tests yet, don't fail CI + + # ==================== + # Build Verification + # ==================== + build: + name: Build Verification + runs-on: ubuntu-latest + needs: [frontend, rust] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install frontend dependencies + run: pnpm install --frozen-lockfile + + - name: Build frontend + run: pnpm build + + - name: Verify build output + run: | + if [ ! -d "apps/desktop/dist" ]; then + echo "::error::Frontend build output not found" + exit 1 + fi + echo "✅ Frontend build successful" + + # ==================== + # Security Audit + # ==================== + security: + name: Security Audit + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run npm audit + run: pnpm audit --audit-level=high + continue-on-error: true + + - name: Run cargo audit + uses: actions-rs/cargo@v1 + with: + command: audit + continue-on-error: true + + # ==================== + # PR Labels + # ==================== + labeler: + name: Label PR + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + needs: [frontend, rust] + + permissions: + contents: read + pull-requests: write + + steps: + - name: Label based on files changed + uses: actions/labeler@v5 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: .github/labeler.yml \ No newline at end of file diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml new file mode 100644 index 0000000..216659d --- /dev/null +++ b/.github/workflows/code-quality.yml @@ -0,0 +1,136 @@ +# Code Quality workflow for AlphaForge +# Runs code quality checks on pull requests + +name: Code Quality + +on: + pull_request: + branches: [main] + +jobs: + # ==================== + # Code Coverage + # ==================== + coverage: + name: Coverage Report + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run tests with coverage + run: pnpm test --coverage + continue-on-error: true + + - name: Upload coverage + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage/ + retention-days: 7 + + # ==================== + # Bundle Size Check + # ==================== + bundle-size: + name: Bundle Size Check + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build + + - name: Check bundle size + run: | + DIST_SIZE=$(du -sb apps/desktop/dist | cut -f1) + MAX_SIZE=5242880 # 5MB + + echo "Bundle size: $DIST_SIZE bytes ($((DIST_SIZE / 1024)) KB)" + + if [ "$DIST_SIZE" -gt "$MAX_SIZE" ]; then + echo "::warning::Bundle size exceeds 5MB limit" + else + echo "✅ Bundle size within limits" + fi + + # ==================== + # Complexity Check + # ==================== + complexity: + name: Code Complexity + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Check file sizes + run: | + echo "### Largest TypeScript files:" + find . -name "*.ts" -o -name "*.tsx" | grep -v node_modules | grep -v dist | xargs wc -l 2>/dev/null | sort -rn | head -10 + + echo "" + echo "### Largest Rust files:" + find . -name "*.rs" | grep -v target | xargs wc -l 2>/dev/null | sort -rn | head -10 + + - name: Check for long functions + run: | + echo "Checking for potentially complex code..." + + # Check for files over 500 lines + LARGE_FILES=$(find . -name "*.ts" -o -name "*.tsx" -o -name "*.rs" | grep -v node_modules | grep -v target | xargs wc -l 2>/dev/null | awk '$1 > 500 {print}') + + if [ -n "$LARGE_FILES" ]; then + echo "::warning::Found files over 500 lines. Consider refactoring:" + echo "$LARGE_FILES" + else + echo "✅ No files exceed 500 lines" + fi + + # ==================== + # TODO/FIXME Check + # ==================== + todos: + name: TODO/FIXME Check + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Find TODOs and FIXMEs + run: | + echo "### TODOs:" + grep -rn "TODO" --include="*.ts" --include="*.tsx" --include="*.rs" . 2>/dev/null | grep -v node_modules | grep -v target || echo "No TODOs found" + + echo "" + echo "### FIXMEs:" + grep -rn "FIXME" --include="*.ts" --include="*.tsx" --include="*.rs" . 2>/dev/null | grep -v node_modules | grep -v target || echo "No FIXMEs found" \ No newline at end of file diff --git a/.github/workflows/pr-agent.yml b/.github/workflows/pr-agent.yml new file mode 100644 index 0000000..9119793 --- /dev/null +++ b/.github/workflows/pr-agent.yml @@ -0,0 +1,150 @@ +# PR-Agent - AI-powered code review automation +# Uses OpenAI-compatible API from api.sfkey.cn +# +# Commands: +# /review - AI code review with security, performance, and quality analysis +# /describe - Generate PR description, title suggestions, and labels +# /improve - Code improvement suggestions +# /ask "..." - Ask questions about the PR +# /test - Generate test suggestions +# /update_changelog - Update CHANGELOG.md + +name: PR-Agent + +on: + pull_request: + types: [opened, reopened, ready_for_review] + pull_request_comment: + types: [created] + issue_comment: + types: [created] + +permissions: + contents: read + pull-requests: write + issues: write + id-token: write + +jobs: + # ==================== + # PR-Agent Review Job + # ==================== + pr-agent: + name: PR-Agent Review + runs-on: ubuntu-latest + if: | + github.event.pull_request.draft == false && + ( + github.event.action == 'opened' || + github.event.action == 'reopened' || + github.event.action == 'ready_for_review' || + contains(github.event.comment.body, '/review') || + contains(github.event.comment.body, '/describe') || + contains(github.event.comment.body, '/improve') || + contains(github.event.comment.body, '/ask') || + contains(github.event.comment.body, '/test') || + contains(github.event.comment.body, '/update_changelog') + ) + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Determine command + id: command + run: | + # Default command for PR open events + COMMAND="review" + + # Check for explicit commands in comments + if [[ "${{ github.event_name }}" == "issue_comment" ]] || \ + [[ "${{ github.event_name }}" == "pull_request_comment" ]]; then + COMMENT="${{ github.event.comment.body }}" + + if echo "$COMMENT" | grep -qE '^/review'; then + COMMAND="review" + elif echo "$COMMENT" | grep -qE '^/describe'; then + COMMAND="describe" + elif echo "$COMMENT" | grep -qE '^/improve'; then + COMMAND="improve" + elif echo "$COMMENT" | grep -qE '^/ask'; then + # Extract the question + COMMAND="ask" + elif echo "$COMMENT" | grep -qE '^/test'; then + COMMAND="test" + elif echo "$COMMENT" | grep -qE '^/update_changelog'; then + COMMAND="update_changelog" + fi + fi + + echo "command=$COMMAND" >> $GITHUB_OUTPUT + echo "Running PR-Agent command: $COMMAND" + + - name: Run PR-Agent + uses: the-pr-agent/pr-agent@main + env: + # ===== OpenAI API Configuration ===== + # API Key - MUST be set in GitHub Secrets as OPENAI_KEY + # Go to: Repository → Settings → Secrets and variables → Actions → New repository secret + OPENAI_KEY: ${{ secrets.OPENAI_KEY }} + + # API Base URL - Custom OpenAI-compatible endpoint + # For api.sfkey.cn, use: https://api.sfkey.cn/v1 + OPENAI_API_BASE: ${{ secrets.OPENAI_API_BASE }} + + # ===== GitHub Configuration ===== + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB.BASE_URL: "https://api.github.com" + + # ===== Model Configuration ===== + # Primary model + CONFIG.MODEL: "gpt-4o" + # Fallback model + CONFIG.FALLBACK_MODELS: '["gpt-4o-mini"]' + + # ===== Token Limits ===== + CONFIG.MAX_MODEL_TOKENS: "128000" + CONFIG.MAX_DESCRIPTION_TOKENS: "500" + CONFIG.MAX_COMMITS_TOKENS: "500" + + # ===== AI Parameters ===== + CONFIG.TEMPERATURE: "0.2" + CONFIG.SEED: "-1" + CONFIG.AI_TIMEOUT: "180" + + # ===== Response Language ===== + CONFIG.RESPONSE_LANGUAGE: "en-US" + + # ===== Repository Context ===== + CONFIG.REPO_CONTEXT_FILES: '["AGENTS.md"]' + CONFIG.REPO_CONTEXT_FROM_DEFAULT_BRANCH: "true" + CONFIG.REPO_CONTEXT_MAX_LINES: "800" + + # ===== Review Settings ===== + PR_REVIEWER.REQUIRE_SCORE_REVIEW: "true" + PR_REVIEWER.REQUIRE_TESTS_REVIEW: "true" + PR_REVIEWER.REQUIRE_SECURITY_REVIEW: "true" + PR_REVIEWER.NUM_MAX_FINDINGS: "5" + PR_REVIEWER.PERSISTENT_COMMENT: "true" + + # ===== Description Settings ===== + PR_DESCRIPTION.PUBLISH_LABELS: "true" + PR_DESCRIPTION.GENERATE_AI_TITLE: "false" + PR_DESCRIPTION.ENABLE_PR_DIAGRAM: "true" + PR_DESCRIPTION.ENABLE_SEMANTIC_FILES_TYPES: "true" + + # ===== Code Suggestions ===== + PR_CODE_SUGGESTIONS.FOCUS_ONLY_ON_PROBLEMS: "true" + PR_CODE_SUGGESTIONS.DEMAND_CODE_SUGGESTIONS_SELF_REVIEW: "true" + PR_CODE_SUGGESTIONS.SUGGESTIONS_SCORE_THRESHOLD: "0" + + # ===== Output Settings ===== + CONFIG.PUBLISH_OUTPUT: "true" + CONFIG.PUBLISH_OUTPUT_PROGRESS: "true" + CONFIG.VERBOSITY_LEVEL: "0" + + with: + # The PR URL to analyze + pr_url: ${{ github.event.pull_request.html_url || format('{0}/pull/{1}', github.server_url, github.event.issue.number) }} \ No newline at end of file diff --git a/.github/workflows/pr-automation.yml b/.github/workflows/pr-automation.yml new file mode 100644 index 0000000..b4c4794 --- /dev/null +++ b/.github/workflows/pr-automation.yml @@ -0,0 +1,170 @@ +# PR Automation - Smart automation for pull requests +# Provides intelligent review assistance and automation + +name: PR Automation + +on: + pull_request: + types: [opened, synchronize, ready_for_review] + pull_request_review: + types: [submitted] + +jobs: + # ==================== + # Auto-Review Reminder + # ==================== + review-reminder: + name: Review Reminder + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + + permissions: + pull-requests: write + + steps: + - name: Check review status + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.issue.number; + + // Get PR details + const pr = await github.rest.pulls.get({ + owner, + repo, + pull_number: prNumber + }); + + // Check if waiting for review for more than 24 hours + const createdAt = new Date(pr.data.created_at); + const now = new Date(); + const hoursSinceCreation = (now - createdAt) / (1000 * 60 * 60); + + if (hoursSinceCreation > 24 && pr.data.requested_reviewers.length > 0) { + const reviewers = pr.data.requested_reviewers.map(r => `@${r.login}`).join(' '); + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: `⏰ This PR has been waiting for review for over 24 hours.\n\nReviewers: ${reviewers}` + }); + } + + # ==================== + # Merge Readiness Check + # ==================== + merge-check: + name: Merge Readiness + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + + permissions: + contents: read + pull-requests: write + statuses: write + + steps: + - name: Check merge readiness + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.issue.number; + + // Get PR details + const pr = await github.rest.pulls.get({ + owner, + repo, + pull_number: prNumber + }); + + // Get reviews + const reviews = await github.rest.pulls.listReviews({ + owner, + repo, + pull_number: prNumber + }); + + // Get check runs + const checkRuns = await github.rest.check.listForRef({ + owner, + repo, + ref: pr.data.head.sha + }); + + // Check merge requirements + const hasApproval = reviews.data.some(r => r.state === 'APPROVED'); + const allChecksPassed = checkRuns.data.check_runs.every(c => c.conclusion === 'success' || c.status !== 'completed'); + const noConflicts = pr.data.mergeable !== false; + + const isReadyToMerge = hasApproval && allChecksPassed && noConflicts && !pr.data.draft; + + // Create status check + await github.rest.repos.createCommitStatus({ + owner, + repo, + sha: pr.data.head.sha, + state: isReadyToMerge ? 'success' : 'pending', + target_url: `https://github.com/${owner}/${repo}/pull/${prNumber}`, + description: isReadyToMerge ? 'Ready to merge' : 'Not ready to merge', + context: 'pr-automation/merge-readiness' + }); + + # ==================== + # Auto-Assignment + # ==================== + auto-assign: + name: Auto-Assign + runs-on: ubuntu-latest + if: github.event.action == 'opened' + + permissions: + contents: read + pull-requests: write + + steps: + - name: Auto-assign reviewers + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.issue.number; + const author = context.payload.pull_request.user.login; + + // Don't auto-assign to the author if they're the only contributor + if (author === 'BerryUIKI') { + console.log('Author is the owner, skipping auto-assignment'); + return; + } + + // Request review from owner + await github.rest.pulls.requestReviewers({ + owner, + repo, + pull_number: prNumber, + reviewers: ['BerryUIKI'] + }); + + # ==================== + # Stale PR Detection + # ==================== + stale-check: + name: Stale PR Check + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + + permissions: + issues: write + pull-requests: write + + steps: + - name: Check for stale PR + uses: actions/stale@v9 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-pr-message: 'This PR has been inactive for 30 days. Please update or close it.' + stale-pr-label: 'stale' + days-before-pr-stale: 30 + days-before-pr-close: -1 # Don't auto-close, just label \ No newline at end of file diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml new file mode 100644 index 0000000..3d2f01f --- /dev/null +++ b/.github/workflows/pr-check.yml @@ -0,0 +1,211 @@ +# PR Auto-Check Workflow +# Runs automated checks on pull requests + +name: PR Check + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +jobs: + # ==================== + # PR Validation + # ==================== + validate: + name: Validate PR + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check PR title format + if: github.event.pull_request.draft == false + run: | + TITLE="${{ github.event.pull_request.title }}" + + # Check conventional commit format + if ! echo "$TITLE" | grep -qE '^(feat|fix|docs|style|refactor|test|chore|perf|build|ci|revert)(\(.+\))?!?: .+'; then + echo "::error::PR title must follow Conventional Commits format" + echo "Expected: feat: description, fix(scope): description, etc." + echo "Got: $TITLE" + exit 1 + fi + echo "✅ PR title format is valid: $TITLE" + + - name: Check for large PRs + run: | + CHANGED_FILES=$(git diff --name-only origin/main...HEAD | wc -l) + CHANGED_LINES=$(git diff --stat origin/main...HEAD | tail -1 | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo "0") + + echo "Changed files: $CHANGED_FILES" + echo "Changed lines: $CHANGED_LINES" + + if [ "$CHANGED_FILES" -gt 50 ]; then + echo "::warning::Large PR detected ($CHANGED_FILES files changed). Consider splitting into smaller PRs." + fi + + - name: Check for forbidden patterns + run: | + # Check for secrets (excluding GitHub Actions syntax) + if git diff origin/main...HEAD | grep -iE '(password|api_key|credential)' | grep -v '# ' | grep -v 'secrets\.' | grep -v 'GITHUB_TOKEN'; then + echo "::error::Potential secrets detected in diff" + exit 1 + fi + + # Check for .env files + if git diff --name-only origin/main...HEAD | grep -E '\.env$|\.env\.'; then + echo "::error::.env files should not be committed" + exit 1 + fi + + echo "✅ No forbidden patterns detected" + + # ==================== + # Branch Protection Check + # ==================== + branch-check: + name: Branch Check + runs-on: ubuntu-latest + + steps: + - name: Check branch + run: | + HEAD_REF="${{ github.head_ref }}" + + # Check branch naming convention + if ! echo "$HEAD_REF" | grep -qE '^(feature|fix|docs|refactor|test|chore)/.+'; then + echo "::warning::Branch name '$HEAD_REF' doesn't follow convention" + echo "Recommended: feature/description, fix/bug-description, docs/topic" + fi + + # Check for direct main branch PR + if [ "${{ github.base_ref }}" == "main" ]; then + echo "✅ PR targets main branch correctly" + fi + + # ==================== + # Size Label + # ==================== + size-label: + name: Size Label + runs-on: ubuntu-latest + if: github.event.pull_request.draft == false + + permissions: + contents: read + pull-requests: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get PR size + id: size + run: | + ADDITIONS=$(git diff --numstat origin/main...HEAD | awk '{sum+=$1} END {print sum}') + DELETIONS=$(git diff --numstat origin/main...HEAD | awk '{sum+=$2} END {print sum}') + TOTAL=$(( ADDITIONS + DELETIONS )) + + echo "additions=$ADDITIONS" >> $GITHUB_OUTPUT + echo "deletions=$DELETIONS" >> $GITHUB_OUTPUT + echo "total=$TOTAL" >> $GITHUB_OUTPUT + + # Determine size label + if [ "$TOTAL" -lt 100 ]; then + echo "label=size/XS" >> $GITHUB_OUTPUT + elif [ "$TOTAL" -lt 300 ]; then + echo "label=size/S" >> $GITHUB_OUTPUT + elif [ "$TOTAL" -lt 800 ]; then + echo "label=size/M" >> $GITHUB_OUTPUT + elif [ "$TOTAL" -lt 1500 ]; then + echo "label=size/L" >> $GITHUB_OUTPUT + else + echo "label=size/XL" >> $GITHUB_OUTPUT + fi + + - name: Apply size label + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.issue.number; + const sizeLabel = '${{ steps.size.outputs.label }}'; + + // Remove existing size labels + const existingLabels = await github.rest.issues.listLabelsOnIssue({ + owner, + repo, + issue_number: prNumber + }); + + for (const label of existingLabels.data) { + if (label.name.startsWith('size/')) { + await github.rest.issues.removeLabel({ + owner, + repo, + issue_number: prNumber, + name: label.name + }); + } + } + + // Add new size label + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: prNumber, + labels: [sizeLabel] + }); + + # ==================== + # Welcome Message + # ==================== + welcome: + name: Welcome + runs-on: ubuntu-latest + if: github.event.action == 'opened' + + permissions: + pull-requests: write + + steps: + - name: Add welcome comment + uses: actions/github-script@v7 + with: + script: | + const { owner, repo } = context.repo; + const prNumber = context.issue.number; + const author = context.payload.pull_request.user.login; + + const message = `## 👋 Welcome, @${author}! + + Thank you for opening this Pull Request! + + ### 📋 Checklist before review: + - [ ] PR follows the [Minimal PR Principle](https://github.com/BerryUIKI/alpha-forge/blob/main/docs/PR_BEST_PRACTICES.md) + - [ ] Conventional Commit format in title + - [ ] All CI checks pass + - [ ] Documentation updated (if applicable) + - [ ] No secrets or sensitive data + + ### 🔒 Branch Protection + **Main branch is protected.** This PR requires: + - ✅ At least 1 approval + - ✅ All CI checks passing + - ✅ Linear history (squash and merge recommended) + + --- + _Automated by AlphaForge CI_ + `; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: message + }); \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..88fb0dd --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,118 @@ +# Release workflow for AlphaForge +# Creates GitHub releases on version tags + +name: Release + +on: + push: + tags: + - 'v*.*.*' + +permissions: + contents: write + +jobs: + # ==================== + # Create Release + # ==================== + release: + name: Create Release + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get version + id: version + run: | + VERSION=${GITHUB_REF#refs/tags/v} + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Extract changelog + id: changelog + run: | + # Extract changelog section for this version + CHANGELOG=$(sed -n "/^## \[${{ steps.version.outputs.version }}\]/,/^## \[/p" CHANGELOG.md | sed '1d;$d') + + # If no changelog entry, use default + if [ -z "$CHANGELOG" ]; then + CHANGELOG="Release v${{ steps.version.outputs.version }}" + fi + + # Write to file for multiline string support + echo "$CHANGELOG" > /tmp/release_notes.md + + - name: Create GitHub Release + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const releaseNotes = fs.readFileSync('/tmp/release_notes.md', 'utf8'); + const version = '${{ steps.version.outputs.version }}'; + + const release = await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: `v${version}`, + name: `AlphaForge v${version}`, + body: releaseNotes, + draft: false, + prerelease: version.includes('-'), + generate_release_notes: false + }); + + console.log(`Created release: ${release.data.html_url}`); + + # ==================== + # Build Release Artifacts + # ==================== + build: + name: Build (${{ matrix.platform }}) + runs-on: ${{ matrix.platform }} + needs: release + + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Install frontend dependencies + run: pnpm install --frozen-lockfile + + - name: Build Tauri app + uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tagName: ${{ github.ref_name }} + releaseName: "AlphaForge ${{ github.ref_name }}" + releaseBody: "See CHANGELOG.md for details" + releaseDraft: false + prerelease: false + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: alphaforge-${{ matrix.platform }} + path: | + apps/desktop/src-tauri/target/release/bundle/ + retention-days: 30 \ No newline at end of file diff --git a/.pr_agent.toml b/.pr_agent.toml new file mode 100644 index 0000000..bee07ec --- /dev/null +++ b/.pr_agent.toml @@ -0,0 +1,162 @@ +# PR-Agent Configuration for AlphaForge +# Uses OpenAI-compatible API from api.sfkey.cn + +# ==================== +# Core Configuration +# ==================== +[config] +# Model selection - use gpt-4o for best quality, gpt-4o-mini for speed +model = "gpt-4o" +fallback_models = ["gpt-4o-mini"] + +# Git provider +git_provider = "github" + +# Output settings +publish_output = true +publish_output_progress = true +verbosity_level = 0 + +# Token limits +max_description_tokens = 500 +max_commits_tokens = 500 +max_model_tokens = 128000 + +# Response language +response_language = "en-US" # English responses + +# AI parameters +temperature = 0.2 +seed = -1 + +# Timeout +ai_timeout = 180 # 3 minutes + +# Include repository context files +repo_context_files = ["AGENTS.md"] +repo_context_from_default_branch = true +repo_context_max_lines = 800 + +# ==================== +# GitHub Configuration +# ==================== +[github] +deployment_type = "user" +base_url = "https://api.github.com" +publish_inline_comments_fallback_with_verification = true +try_fix_invalid_inline_comments = true +ignore_bot_pr = true + +# ==================== +# GitHub Actions Auto-trigger +# ==================== +[github_action_config] +# Auto-run on PR open +auto_review = true +auto_describe = true +auto_improve = false # Manual trigger only for improve + +# Trigger actions +pr_actions = ["opened", "reopened", "ready_for_review"] + +# ==================== +# Review Settings +# ==================== +[pr_reviewer] +# Enable review features +require_score_review = true +require_tests_review = true +require_estimate_effort_to_review = true +require_security_review = true +require_ticket_analysis_review = true + +# Review output +publish_output_no_suggestions = true +persistent_comment = true +num_max_findings = 5 + +# Review labels +enable_review_labels_security = true +enable_review_labels_effort = true + +# Help text +enable_intro_text = true +enable_help_text = false + +# ==================== +# Description Settings +# ==================== +[pr_description] +publish_labels = true +add_original_user_description = true +generate_ai_title = false +use_bullet_points = true +enable_pr_type = true +enable_pr_diagram = true + +# Walkthrough +enable_semantic_files_types = true +collapsible_file_list = "adaptive" +collapsible_file_list_threshold = 6 + +# ==================== +# Code Suggestions +# ==================== +[pr_code_suggestions] +commitable_code_suggestions = false +focus_only_on_problems = true +max_history_len = 4 +publish_output_no_suggestions = true +suggestions_score_threshold = 0 + +# Extended mode +auto_extended_mode = true +num_code_suggestions_per_chunk = 3 +max_number_of_calls = 3 +parallel_calls = true + +# Self-review checkbox +demand_code_suggestions_self_review = true +code_suggestions_self_review_text = "**Author self-review**: I have reviewed the PR code suggestions and addressed the relevant ones." +approve_pr_on_self_review = false +fold_suggestions_on_self_review = true + +# ==================== +# Questions Settings +# ==================== +[pr_questions] +use_conversation_history = true + +# ==================== +# Update Changelog +# ==================== +[pr_update_changelog] +push_changelog_changes = false +add_pr_link = true +skip_ci_on_push = true + +# ==================== +# Test Generation +# ==================== +[pr_test] +num_tests = 3 +avoid_mocks = true + +# ==================== +# Best Practices +# ==================== +[best_practices] +max_lines_allowed = 800 +enable_global_best_practices = true + +[auto_best_practices] +enable_auto_best_practices = true +utilize_auto_best_practices = true +max_patterns = 5 + +# ==================== +# Artifacts (for CI results) +# ==================== +[artifacts] +enable = false +max_artifact_size = 50000 \ No newline at end of file diff --git a/apps/desktop/src-tauri/src/services/workspace_service.rs b/apps/desktop/src-tauri/src/services/workspace_service.rs index 388dd4f..003001e 100644 --- a/apps/desktop/src-tauri/src/services/workspace_service.rs +++ b/apps/desktop/src-tauri/src/services/workspace_service.rs @@ -70,7 +70,7 @@ impl WorkspaceService { } // Validate name if provided - let name = input.name.as_ref().map(|n| n.trim()).filter(|n| !n.is_empty()); + let name = input.name.map(|n| n.trim().to_string()).filter(|n| !n.is_empty()); let name = match name { Some(n) if n.len() > 200 => { @@ -78,7 +78,7 @@ impl WorkspaceService { "Workspace name cannot exceed 200 characters".to_string(), )); } - Some(n) => n.to_string(), + Some(n) => n, None => { return Err(AppError::Validation( "Workspace name must be provided".to_string(), diff --git a/crates/domain/src/lib.rs b/crates/domain/src/lib.rs index 3cebf30..ae92551 100644 --- a/crates/domain/src/lib.rs +++ b/crates/domain/src/lib.rs @@ -3,9 +3,9 @@ // Contains shared domain types: Research, Thesis, Portfolio, Artifact, Task, Workspace. // These are pure data structures with no I/O dependencies. -pub mod research; -pub mod thesis; -pub mod portfolio; pub mod artifact; +pub mod portfolio; +pub mod research; pub mod task; +pub mod thesis; pub mod workspace; diff --git a/crates/domain/src/workspace.rs b/crates/domain/src/workspace.rs index 70826dc..8a45ad3 100644 --- a/crates/domain/src/workspace.rs +++ b/crates/domain/src/workspace.rs @@ -31,4 +31,4 @@ pub struct CreateWorkspaceInput { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UpdateWorkspaceInput { pub name: Option, -} \ No newline at end of file +} diff --git a/docs/CI_CD.md b/docs/CI_CD.md new file mode 100644 index 0000000..9db0c37 --- /dev/null +++ b/docs/CI_CD.md @@ -0,0 +1,317 @@ +# CI/CD Configuration + +This document describes the Continuous Integration and Continuous Deployment (CI/CD) setup for AlphaForge (Investment OS). + +## 📋 Table of Contents + +- [Overview](#overview) +- [Workflows](#workflows) +- [Branch Protection](#branch-protection) +- [PR Automation](#pr-automation) +- [Dependabot](#dependabot) +- [Required Setup](#required-setup) + +--- + +## Overview + +AlphaForge uses **GitHub Actions** for CI/CD with comprehensive automation for: + +- ✅ Code quality checks (lint, typecheck, format) +- ✅ Test execution (frontend + backend) +- ✅ Build verification +- ✅ Security auditing +- ✅ PR validation and automation +- ✅ Automated dependency updates +- ✅ Release management + +--- + +## Workflows + +### 1. CI Workflow (`ci.yml`) + +**Triggers:** Push to `main`, Pull Requests to `main` + +**Jobs:** + +| Job | Description | Steps | +|-----|-------------|-------| +| `frontend` | TypeScript/React checks | typecheck, lint, test | +| `rust` | Rust checks | fmt, clippy, build, test | +| `build` | Build verification | frontend build, artifact check | +| `security` | Security audit | npm audit, cargo audit | +| `labeler` | Auto-label PRs | file-based labeling | + +**Concurrency:** Cancels in-progress runs on new commits + +--- + +### 2. PR Check Workflow (`pr-check.yml`) + +**Triggers:** PR opened, synchronized, reopened, ready_for_review + +**Jobs:** + +| Job | Description | +|-----|-------------| +| `validate` | PR title format (Conventional Commits), large PR warning, forbidden patterns | +| `branch-check` | Branch naming convention check | +| `size-label` | Automatic size label (XS/S/M/L/XL) | +| `welcome` | Welcome message on new PRs | + +--- + +### 3. PR Automation Workflow (`pr-automation.yml`) + +**Triggers:** PR events, reviews + +**Jobs:** + +| Job | Description | +|-----|-------------| +| `review-reminder` | Remind after 24h waiting for review | +| `merge-check` | Create merge readiness status check | +| `auto-assign` | Auto-assign reviewers on new PRs | +| `stale-check` | Label stale PRs after 30 days | + +--- + +### 4. Code Quality Workflow (`code-quality.yml`) + +**Triggers:** Pull Requests to `main` + +**Jobs:** + +| Job | Description | +|-----|-------------| +| `coverage` | Test coverage report | +| `bundle-size` | Bundle size check (< 5MB) | +| `complexity` | File size and complexity warnings | +| `todos` | TODO/FIXME tracking | + +--- + +### 5. Release Workflow (`release.yml`) + +**Triggers:** Push of version tags (`v*.*.*`) + +**Jobs:** + +| Job | Description | +|-----|-------------| +| `release` | Create GitHub Release with changelog | +| `build` | Build cross-platform binaries (Linux, macOS, Windows) | + +--- + +## Branch Protection + +### `main` Branch Rules + +The `main` branch is protected with the following rules: + +1. **Direct pushes blocked** - All changes via PR +2. **Required status checks:** + - Frontend CI (typecheck, lint) + - Rust CI (fmt, clippy, build) + - Build verification +3. **Required approvals:** At least 1 +4. **Linear history:** Required (squash merge recommended) +5. **Conversation resolution:** Required + +### Setup in GitHub UI + +Go to: **Settings → Branches → Branch protection rules → main** + +Configure: +- ✅ Require a pull request before merging + - ✅ Require approvals: 1 + - ✅ Dismiss stale pull request approvals when new commits are pushed + - ✅ Require review from Code Owners +- ✅ Require status checks to pass before merging + - Select: `frontend`, `rust`, `build` +- ✅ Require branches to be up to date before merging +- ✅ Require linear history +- ✅ Require conversation resolution before merging + +--- + +## PR Automation + +### Auto-Labeling + +Labels are automatically applied based on changed files: + +| Label | Trigger Files | +|-------|---------------| +| `frontend` | `*.ts`, `*.tsx`, `packages/` | +| `backend` | `*.rs`, `Cargo.toml` | +| `rust` | `*.rs` | +| `typescript` | `*.ts`, `*.tsx` | +| `documentation` | `docs/`, `README*.md` | +| `database` | `migrations/`, `database/` | +| `ci` | `.github/workflows/`, `scripts/` | +| `plugins` | `plugins/` | +| `tests` | `*.test.*`, `*.spec.*` | +| `security` | `security/`, `capabilities/` | +| `ui` | `styles/`, `components/` | +| `config` | `package.json`, `*.config.*` | + +### Size Labels + +| Label | Lines Changed | +|-------|---------------| +| `size/XS` | < 100 | +| `size/S` | 100-299 | +| `size/M` | 300-799 | +| `size/L` | 800-1499 | +| `size/XL` | ≥ 1500 | + +### PR Title Format + +PR titles must follow [Conventional Commits](https://www.conventionalcommits.org/): + +``` +feat: add new feature +fix(scope): bug description +docs: update documentation +chore: routine maintenance +``` + +Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`, `perf`, `build`, `ci`, `revert` + +--- + +## Dependabot + +### Configuration + +Dependabot checks for updates weekly on Mondays at 09:00 Asia/Shanghai: + +| Ecosystem | Directory | Limit | +|-----------|-----------|-------| +| npm/pnpm | `/` | 10 PRs | +| cargo | `/` | 5 PRs | +| GitHub Actions | `/` | 5 PRs | + +### Grouping + +Dependencies are grouped: +- **Production dependencies** - grouped together +- **Development dependencies** - grouped together + +### Review + +All Dependabot PRs are: +- Assigned to: @BerryUIKI +- Reviewed by: @BerryUIKI +- Labeled: `dependencies`, `frontend`/`rust`/`ci` + +--- + +## Required Setup + +### 1. Enable GitHub Actions + +Go to: **Settings → Actions → General** + +- ✅ Allow all actions and reusable workflows +- ✅ Allow actions created by GitHub +- ✅ Allow actions by Marketplace verified creators + +### 2. Branch Protection + +Configure branch protection as described above. + +### 3. Secrets + +No secrets are required for basic CI. For releases: + +- `GITHUB_TOKEN` - automatically provided by GitHub Actions + +### 4. CODEOWNERS + +The `.github/CODEOWNERS` file assigns ownership: + +- Default owner: @BerryUIKI +- Specific paths have designated owners + +### 5. Enable Dependabot + +Go to: **Settings → Security → Code security and analysis** + +- ✅ Enable Dependabot security updates +- ✅ Enable Dependabot version updates + +### 6. Merge Settings + +Go to: **Settings → Pull Requests** + +- ✅ Allow squash merging (recommended) +- ✅ Allow merge commits (optional) +- ❌ Allow rebase merging (not recommended for linear history) + +**Squash merge commit message:** +- ✅ Default to PR title + +--- + +## Monitoring + +### Workflow Status + +Monitor workflow runs at: `Actions` tab in GitHub + +### Badges + +Add to README.md: + +```markdown +[![CI](https://github.com/BerryUIKI/alpha-forge/workflows/CI/badge.svg)](https://github.com/BerryUIKI/alpha-forge/actions/workflows/ci.yml) +[![Release](https://github.com/BerryUIKI/alpha-forge/workflows/Release/badge.svg)](https://github.com/BerryUIKI/alpha-forge/actions/workflows/release.yml) +``` + +--- + +## Troubleshooting + +### CI Fails on Empty Tests + +The CI is configured with `continue-on-error: true` for tests since no tests exist yet. Remove this once tests are added. + +### Build Fails on Tauri + +Tauri builds require platform-specific tooling: +- **Linux**: `libwebkit2gtk-4.0-dev`, `libssl-dev`, etc. +- **macOS**: Xcode Command Line Tools +- **Windows**: Microsoft Visual Studio C++ Build Tools + +See: https://tauri.app/v1/guides/getting-started/prerequisites + +### Dependabot Not Creating PRs + +Check that: +1. Dependabot is enabled in repository settings +2. `dependabot.yml` is in `.github/` directory +3. Repository is not archived + +--- + +## Future Improvements + +- [ ] Add code coverage reporting (Codecov/Coveralls) +- [ ] Add performance benchmarks +- [ ] Add visual regression testing +- [ ] Add dependency license checking +- [ ] Add automated changelog generation +- [ ] Add Slack/Discord notifications +- [ ] Add artifact signing for releases + +--- + +## Related Documentation + +- [CONTRIBUTING.md](../CONTRIBUTING.md) - Contribution guide +- [PR_BEST_PRACTICES.md](PR_BEST_PRACTICES.md) - PR guidelines +- [GIT_WORKFLOW.md](GIT_WORKFLOW.md) - Git workflow \ No newline at end of file diff --git a/docs/PR_AGENT_QUICKSTART.md b/docs/PR_AGENT_QUICKSTART.md new file mode 100644 index 0000000..5e11fc9 --- /dev/null +++ b/docs/PR_AGENT_QUICKSTART.md @@ -0,0 +1,58 @@ +# PR-Agent Quick Setup Card + +## 🚀 Quick Start (For Maintainers) + +### 1. Configure GitHub Secrets + +Go to: **Settings → Secrets and variables → Actions → New repository secret** + +Add these two Secrets: + +| Name | Value | +|------|-------| +| `OPENAI_KEY` | `Contact Berry for the key` | +| `OPENAI_API_BASE` | `https://api.sfkey.cn/v1` | + +### 2. Verify Files Exist + +Ensure these files exist: +- ✅ `.pr_agent.toml` +- ✅ `.github/workflows/pr-agent.yml` + +### 3. Enable GitHub Actions + +**Settings → Actions → General** +- ✅ Allow all actions and reusable workflows + +### 4. Test + +Create a test PR, PR-Agent will automatically review it. + +--- + +## 📋 Available Commands + +Type in PR comments: + +| Command | Function | +|---------|----------| +| `/review` | Code review | +| `/describe` | Generate description | +| `/improve` | Improvement suggestions | +| `/ask "question"` | Ask questions | +| `/test` | Test suggestions | + +--- + +## ⚠️ Security Reminder + +- API key has been shared via secure channel +- **NEVER** commit the key to the repository +- If leaked, notify Berry immediately to revoke the key + +--- + +## 📞 Contact + +- GitHub: @BerryUIKI +- Issues: https://github.com/BerryUIKI/alpha-forge/issues \ No newline at end of file diff --git a/docs/PR_AGENT_SETUP.md b/docs/PR_AGENT_SETUP.md new file mode 100644 index 0000000..46501b0 --- /dev/null +++ b/docs/PR_AGENT_SETUP.md @@ -0,0 +1,376 @@ +# PR-Agent 配置指南 + +本文档说明如何为 AlphaForge 配置 PR-Agent AI 代码审查助手。 + +## 📋 目录 + +- [概述](#概述) +- [架构说明](#架构说明) +- [配置步骤](#配置步骤) +- [Secrets 配置](#secrets-配置) +- [可用命令](#可用命令) +- [自动触发规则](#自动触发规则) +- [费用估算](#费用估算) +- [故障排查](#故障排查) +- [安全最佳实践](#安全最佳实践) + +--- + +## 概述 + +PR-Agent 是一个 AI 驱动的代码审查助手,可以: + +- ✅ 自动审查 PR 代码(安全、性能、质量) +- ✅ 生成 PR 描述和标签 +- ✅ 提供代码改进建议 +- ✅ 回答关于 PR 的问题 +- ✅ 生成测试建议 +- ✅ 更新 CHANGELOG + +### 本配置使用的 API + +- **提供商**: 随风AI (api.sfkey.cn) +- **兼容性**: OpenAI API 兼容 +- **模型**: GPT-4o(主) / GPT-4o-mini(备选) +- **优势**: 国内访问稳定,无需翻墙 + +--- + +## 架构说明 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ GitHub Repository │ +│ ┌─────────────────────────────────────────────────────┐ │ +│ │ .github/workflows/pr-agent.yml │ │ +│ │ - Trigger: PR opened, comment with /review, etc. │ │ +│ │ - Uses: the-pr-agent/pr-agent@main │ │ +│ └──────────────────────┬──────────────────────────────┘ │ +│ │ │ +│ ┌──────────────────────▼──────────────────────────────┐ │ +│ │ GitHub Secrets (安全存储) │ │ +│ │ - OPENAI_KEY: API 密钥 │ │ +│ │ - OPENAI_API_BASE: API 端点 URL │ │ +│ └──────────────────────┬──────────────────────────────┘ │ +└─────────────────────────┼───────────────────────────────────┘ + │ + │ HTTPS + ▼ + ┌───────────────────────────────┐ + │ api.sfkey.cn (随风AI) │ + │ OpenAI-Compatible Endpoint │ + │ Model: gpt-4o, gpt-4o-mini │ + └───────────────────────────────┘ +``` + +--- + +## 配置步骤 + +### 第一步:确认配置文件已创建 + +以下文件应已在仓库中创建: + +1. **`.pr_agent.toml`** - PR-Agent 配置文件 +2. **`.github/workflows/pr-agent.yml`** - GitHub Actions 工作流 + +### 第二步:获取 API 密钥 + +从 [随风AI](https://api.sfkey.cn) 获取: + +1. 注册并登录账号 +2. 进入控制台获取 API Key +3. 确认可用余额充足 + +### 第三步:配置 GitHub Secrets + +**重要**: 这些配置将在另一个 GitHub 账号执行,你需要将密钥安全地传递给该账号的维护者。 + +#### 在目标仓库配置 Secrets + +前往:**Settings → Secrets and variables → Actions → New repository secret** + +需要配置以下 Secrets: + +| Secret 名称 | 值 | 说明 | +|------------|-----|------| +| `OPENAI_KEY` | `sk-xxxxx` | 随风AI 的 API 密钥 | +| `OPENAI_API_BASE` | `https://api.sfkey.cn/v1` | API endpoint URL | + +> ⚠️ **Security Warning**: +> - Never commit API keys to the repository +> - Use GitHub Secrets for storage, don't hardcode in workflow files +> - Rotate keys regularly + +### 第四步:启用 GitHub Actions + +1. 进入仓库 **Settings → Actions → General** +2. 选择 **Allow all actions and reusable workflows** +3. 保存设置 + +### 第五步:测试配置 + +创建一个测试 PR,PR-Agent 应该会自动: + +1. 分析代码变更 +2. 发布审查评论 +3. 生成 PR 描述建议 + +--- + +## Secrets 配置 + +### OPENAI_KEY + +随风AI 的 API 密钥,格式通常为 `sk-` 开头的字符串。 + +**获取方式**: +1. 登录 https://api.sfkey.cn +2. 进入「API 密钥」页面 +3. 创建或复制密钥 + +**配置示例**: +``` +Name: OPENAI_KEY +Value: sk-xxxxxxxxxxxxxxxxxxxxxxxx +``` + +### OPENAI_API_BASE + +API 端点 URL,使用随风AI 的 OpenAI 兼容端点。 + +**配置值**: +``` +Name: OPENAI_API_BASE +Value: https://api.sfkey.cn/v1 +``` + +**注意**: URL 末尾不要加 `/`,正确是 `/v1` 而不是 `/v1/` + +### GITHUB_TOKEN + +这是 GitHub 自动提供的,无需手动配置。 + +--- + +## 可用命令 + +在 PR 评论区输入以下命令触发相应功能: + +| 命令 | 功能 | 示例 | +|------|------|------| +| `/review` | 完整代码审查 | `/review` | +| `/describe` | 生成 PR 描述 | `/describe` | +| `/improve` | 代码改进建议 | `/improve` | +| `/ask "问题"` | 提问 | `/ask "这个函数的作用是什么?"` | +| `/test` | 生成测试建议 | `/test` | +| `/update_changelog` | 更新变更日志 | `/update_changelog` | +| `/help` | 查看帮助 | `/help` | + +### 命令参数 + +``` +# 只审查特定文件 +/review --files="src/**/*.ts" + +# 指定测试数量 +/test --num_tests=5 + +# 指定测试框架 +/test --testing_framework=vitest + +# 自定义改进建议 +/improve --extra_instructions="关注性能优化" +``` + +--- + +## 自动触发规则 + +PR-Agent 会在以下情况自动运行: + +### 自动触发 + +| 事件 | 动作 | 执行命令 | +|------|------|----------| +| PR 创建 (`opened`) | 自动审查 | `/review` | +| PR 重新打开 (`reopened`) | 自动审查 | `/review` | +| PR 标记为可审查 (`ready_for_review`) | 自动审查 | `/review` | + +### 手动触发 + +在 PR 评论区输入命令(如 `/describe`)手动触发。 + +### 不触发的情况 + +- PR 是草稿状态 (`draft: true`) +- PR 被 `ignore_pr_title` 规则匹配 +- 作者在 `ignore_pr_authors` 列表中 + +--- + +## 费用估算 + +### Token 消耗估算 + +| 操作 | 预估 Token | 预估费用 (GPT-4o) | +|------|-----------|------------------| +| 小型 PR (< 100 行) | ~5,000 tokens | ~$0.03 | +| 中型 PR (100-500 行) | ~15,000 tokens | ~$0.08 | +| 大型 PR (500-1500 行) | ~40,000 tokens | ~$0.20 | +| 超大 PR (> 1500 行) | 可能分段处理 | 变化较大 | + +### 随风AI 价格参考 + +请查看 [随风AI 价格页面](https://api.sfkey.cn/#pricing) 获取最新价格。 + +**建议**: +- 设置 API 消费限额 +- 监控使用量 +- 大型 PR 谨慎使用 `/improve --extended` + +--- + +## 故障排查 + +### 问题:PR-Agent 没有响应 + +**可能原因**: +1. API 密钥未配置或无效 +2. API 余额不足 +3. GitHub Actions 未启用 +4. PR 是草稿状态 + +**解决方法**: +```bash +# 检查 GitHub Actions 日志 +# 进入 Actions 标签页查看错误信息 + +# 手动触发测试 +# 在 PR 评论: /review +``` + +### 问题:API 调用失败 + +**常见错误**: + +| 错误 | 原因 | 解决方法 | +|------|------|----------| +| `401 Unauthorized` | API Key 无效 | 检查 OPENAI_KEY Secret | +| `402 Payment Required` | 余额不足 | 充值或检查配额 | +| `404 Not Found` | API Base URL 错误 | 检查 OPENAI_API_BASE | +| `429 Rate Limit` | 请求过快 | 稍后重试 | +| `500 Server Error` | 服务端问题 | 联系随风AI 支持 | + +### 问题:响应质量不佳 + +**可能原因**: +- 模型选择不合适 +- Token 限制过低 +- 上下文不足 + +**解决方法**: +```toml +# 在 .pr_agent.toml 中调整 +[config] +model = "gpt-4o" # 使用更强的模型 +max_model_tokens = 128000 # 增加 token 限制 +temperature = 0.1 # 降低随机性 + +[pr_reviewer] +num_max_findings = 10 # 增加发现数量 +extra_instructions = "重点关注安全性和性能" # 添加自定义指令 +``` + +--- + +## 安全最佳实践 + +### 🔐 API 密钥安全 + +1. **永远不要**将 API 密钥提交到代码仓库 +2. **使用** GitHub Secrets 存储敏感信息 +3. **定期轮换** API 密钥(建议每 90 天) +4. **限制** API 密钥的权限范围(如果提供商支持) + +### 🛡️ 仓库安全 + +1. **审查** PR-Agent 的建议,不要盲目接受 +2. **限制** 对敏感文件的自动审查(通过配置) +3. **启用** 分支保护规则 +4. **监控** GitHub Actions 执行日志 + +### 📋 Secrets 传递指南 + +当需要将配置交给其他维护者时: + +1. **使用安全的通信渠道**传递密钥: + - 使用端到端加密的消息应用(如 Signal) + - 使用密码管理器的共享功能 + - 不要通过邮件/即时通讯直接发送明文密钥 + +2. **传递内容**: + - API 密钥: `sk-xxxxx` + - API 端点: `https://api.sfkey.cn/v1` + - 配置文件位置: `.pr_agent.toml` + +3. **确认清单**: + - [ ] 接收方已创建 GitHub Secrets + - [ ] 接收方已测试 PR-Agent 工作正常 + - [ ] 传输渠道已销毁消息记录 + +### ⚠️ 紧急情况处理 + +如果 API 密钥泄露: + +1. **立即**在随风AI 控制台撤销密钥 +2. **更新** GitHub Secrets 中的密钥 +3. **检查** API 使用日志是否有异常 +4. **通知**仓库维护者 + +--- + +## 配置文件说明 + +### `.pr_agent.toml` + +仓库根目录的配置文件,定义 PR-Agent 的行为: + +```toml +[config] +model = "gpt-4o" # 使用的模型 +response_language = "zh-CN" # 响应语言 + +[pr_reviewer] +require_security_review = true # 启用安全审查 +num_max_findings = 5 # 最多发现 5 个问题 + +[pr_description] +publish_labels = true # 自动发布标签 +generate_ai_title = false # 不自动生成标题 +``` + +### `.github/workflows/pr-agent.yml` + +GitHub Actions 工作流文件,定义触发条件和环境变量。 + +--- + +## 相关链接 + +- [PR-Agent GitHub](https://github.com/Codium-ai/pr-agent) +- [PR-Agent 文档](https://github.com/Codium-ai/pr-agent/blob/main/README.md) +- [随风AI 文档](https://api.sfkey.cn/#docs) +- [AlphaForge CI/CD 文档](./CI_CD.md) + +--- + +## 更新日志 + +| 日期 | 变更 | +|------|------| +| 2026-08-01 | 初始配置,使用 api.sfkey.cn 端点 | + +--- + +**需要帮助?** 在 [GitHub Discussions](https://github.com/BerryUIKI/alpha-forge/discussions) 提问。 \ No newline at end of file diff --git a/package.json b/package.json index 8ead3f4..412ace6 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "dev:web": "cd apps/desktop && npm run dev", "build": "cd apps/desktop && npm run build", "lint": "eslint . --ext .ts,.tsx", - "typecheck": "npm run typecheck -w @investment-os/desktop", + "typecheck": "pnpm run typecheck --filter @investment-os/desktop", "test": "vitest run", "test:watch": "vitest", "format": "prettier --write .", diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 94ffa54..3fe7418 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,3 @@ [toolchain] -channel = "stable-x86_64-pc-windows-msvc" +channel = "stable" components = ["rustfmt", "clippy", "rust-analyzer"] -targets = ["x86_64-pc-windows-msvc"]