diff --git a/.claude/commands/netlify-build-check.md b/.claude/commands/netlify-build-check.md new file mode 100644 index 00000000000..22e1935081f --- /dev/null +++ b/.claude/commands/netlify-build-check.md @@ -0,0 +1,240 @@ +--- +description: Check PR build status, analyze failures, and propose fixes +allowed-tools: Bash, Read, Glob, Grep, Task, AskUserQuestion, WebFetch +argument-hint: [--pr=NUMBER (auto)] +--- + +# Netlify Build Check Command + +Check CI/CD build status for a PR, analyze any failures, and propose fixes. + +## Context +- Current branch: !`git branch --show-current` +- Arguments: $ARGUMENTS + +## Phase 1: Identify PR and Repo + +### Get Repo Info +```bash +REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner) +# Returns: owner/repo (e.g., ethereum/ethereum-org-website) +``` + +### Parse Arguments +Extract `PR_NUMBER` from `--pr=NUMBER` or auto-detect: + +```bash +if [[ -z "$PR_NUMBER" ]]; then + PR_NUMBER=$(gh pr view --json number -q .number 2>/dev/null) +fi +``` + +If no PR found, error: "No PR detected. Use --pr=NUMBER or run from a PR branch." + +Report: "Checking build status for PR #{PR_NUMBER}" + +## Phase 2: Check Netlify Build Status + +Get the Netlify deploy preview check for the PR: + +```bash +gh pr checks $PR_NUMBER --json name,state,link -q '.[] | select(.name | test("netlify"; "i"))' +``` + +The Netlify check is typically named `netlify/ethereumorg/deploy-preview`. + +### Determine Status + +Parse the Netlify check result: +- **Passed** → Report "Netlify build passed" and exit +- **Pending** → Report that build is still running, ask if user wants to wait or proceed +- **Failure** → Continue to Phase 3 + +Report status: +``` +Netlify Build Status: FAILURE +Check: netlify/ethereumorg/deploy-preview +Details: https://app.netlify.com/... +``` + +## Phase 3: Fetch Netlify Build Logs + +### Option A: Check Details URL (Primary) + +Use the `link` from the Netlify check to fetch logs: + +```bash +DETAILS_URL=$(gh pr checks $PR_NUMBER --json name,state,link -q '.[] | select(.name | test("netlify"; "i")) | .link') +``` + +Then use WebFetch with the details URL to extract error information from the Netlify deploy logs. + +### Option B: Netlify Bot Comment (Fallback) + +Netlify posts deploy status as PR comments. Fetch them: + +```bash +gh pr view $PR_NUMBER --json comments -q '.comments[].body' | \ + grep -i -A 100 "netlify" +``` + +The Netlify bot comment typically includes: +- Deploy preview URL +- Build status summary +- Link to full deploy logs + +If the comment contains a deploy log URL (e.g., `https://app.netlify.com/sites/.../deploys/...`), use WebFetch to retrieve the build output. + +## Phase 4: Analyze Errors + +Parse the build logs to identify error types. + +### Common Error Patterns + +**TypeScript Errors:** +``` +error TS\d+: .+ +Type '.+' is not assignable to type '.+' +Property '.+' does not exist on type '.+' +Cannot find name '.+' +``` + +**ESLint Errors:** +``` +\d+:\d+\s+error\s+.+eslint +``` + +**Next.js Build Errors:** +``` +Error: .+ in .+ +Failed to compile +Build optimization failed +Module not found: Can't resolve +``` + +**Import/Export Errors:** +``` +Cannot find module '.+' +Module not found +Export '.+' was not found in '.+' +``` + +**Translation/i18n Errors (common in translation PRs):** +``` +SyntaxError: .+ in JSON +Unexpected token +Missing required key +Invalid message format +``` + +**MDX/Markdown Errors:** +``` +Error compiling MDX +Could not parse expression +Unexpected end of file +``` + +For each error found, extract: +- File path +- Line number (if available) +- Error message +- Error type/category + +## Phase 5: Propose Fixes + +For each identified error, read the relevant file from the PR branch and propose a fix. + +### Reading Files from PR Branch + +Use a worktree to access PR files without switching branches: + +```bash +PR_BRANCH=$(gh pr view $PR_NUMBER --json headRefName -q .headRefName) +WORKTREE_PATH=.worktrees/pr-$PR_NUMBER + +# Create worktree if it doesn't exist +if [[ ! -d "$WORKTREE_PATH" ]]; then + git worktree add "$WORKTREE_PATH" "$PR_BRANCH" +fi +``` + +Then read files from `$WORKTREE_PATH/{file_path}`. + +### Fix Proposal Format + +Present fixes in this format: + +```markdown +## Build Error Analysis + +**PR:** #{PR_NUMBER} +**Failed Check:** {CHECK_NAME} +**Errors Found:** {COUNT} + +--- + +### Error 1: {ERROR_TYPE} + +**File:** `{FILE_PATH}:{LINE_NUMBER}` +**Message:** {ERROR_MESSAGE} + +**Current code:** +```{lang} +{CURRENT_CODE_SNIPPET} +``` + +**Proposed fix:** +```{lang} +{FIXED_CODE_SNIPPET} +``` + +**Explanation:** {WHY_THIS_FIXES_IT} + +--- + +(Repeat for each error) +``` + +### Error Categories & Fix Strategies + +**TypeScript type errors:** +- Read the file and surrounding context +- Check type definitions in the codebase (`src/lib/types.ts`, etc.) +- Propose type corrections or proper type assertions + +**Missing imports:** +- Search codebase for the export using Grep +- Propose correct import path + +**Invalid JSON (common in translations):** +- Read the JSON file +- Identify syntax errors (trailing commas, missing quotes, unescaped characters) +- Propose corrected JSON + +**Module not found:** +- Check if file exists at expected path +- Suggest correct path or check if dependency needs installing + +**MDX compilation errors:** +- Check for malformed JSX, unclosed tags, or invalid expressions +- Propose syntax corrections + +## Phase 6: Present Results + +After analyzing errors, use AskUserQuestion to present options: + +**Question:** "Found {N} build errors with proposed fixes. What would you like to do?" + +**Options:** +1. **Show all fixes** - Display detailed fix proposals for review +2. **Focus on first error** - Work through errors one at a time with full context +3. **Export report** - Save analysis to `build-errors-{PR_NUMBER}.md` +4. **Done** - End session (apply fixes manually or ask Claude separately) + +## Notes + +- This command analyzes and proposes fixes but does NOT auto-apply them +- For translation PRs, run this before `/review-translations` if build is failing +- Some build errors may require additional context beyond the logs +- Netlify deploy previews include build logs in PR comments - check there first +- If worktree already exists, reuse it; clean up with `git worktree remove` when done \ No newline at end of file diff --git a/.claude/commands/review-translations.md b/.claude/commands/review-translations.md new file mode 100644 index 00000000000..42bc2e4ea3e --- /dev/null +++ b/.claude/commands/review-translations.md @@ -0,0 +1,405 @@ +--- +description: Review translation imports for quality issues (runs after sanitizer) +allowed-tools: Bash, Read, Glob, Grep, Task, AskUserQuestion +argument-hint: [--pr=NUMBER (auto)] [--scope=pr|full (pr)] [--language=CODE] [--model=opus|sonnet|haiku (opus)] +--- + +# Translation Review Command + +Review translation imports, identifying issues that require human/AI judgment beyond what the deterministic sanitizer can fix. + +## Context +- Current branch: !`git branch --show-current` +- Arguments: $ARGUMENTS + +## Modes of Operation + +### Mode 1: PR Review (Default) +Reviews files changed in a specific PR. +``` +/review-translations # Auto-detect PR, review all languages +/review-translations --pr=16979 # Review specific PR's changed files +/review-translations --scope=full # Review ALL files for languages in PR +``` + +### Mode 2: Filtered PR Review +Reviews only specific language(s) from a PR. +``` +/review-translations --language=hi # Filter auto-detected PR to Hindi only +/review-translations --pr=16979 --language=hi # Review only Hindi files from PR #16979 +/review-translations --pr=16979 --language=hi,bn --scope=full # All Hindi+Bengali files +``` + +### Mode 3: Standalone Language Review +Reviews all files for a language when no PR context is available. +``` +/review-translations --language=es # On dev branch: review all Spanish files +``` + +## Flags + +| Flag | Description | Default | +|------|-------------|---------| +| `--pr=NUMBER` | Specific PR to review | auto-detect from `i18n*` branch | +| `--scope=pr\|full` | `pr` = only PR changed files, `full` = all files for languages | `pr` | +| `--language=CODES` | Filter to specific language(s), comma-separated | all languages in PR | +| `--model=MODEL` | Model for analysis: `opus` (deep), `sonnet` (balanced), `haiku` (fast) | `opus` | + +## Phase 0: Determine Mode and Scope + +### Parse Flags + +Extract from $ARGUMENTS: +- `PR_NUMBER`: from `--pr=NUMBER` or auto-detect +- `LANGUAGE_FILTER`: from `--language=CODES` (comma-separated) or empty +- `SCOPE`: from `--scope=pr|full` (default: `pr`) + +### Determine Mode + +1. **Attempt PR Detection** + - If `--pr=NUMBER` provided → use that PR + - Otherwise, check if branch starts with `i18n`: + ```bash + BRANCH=$(git branch --show-current) + if [[ "$BRANCH" == i18n* ]]; then + PR_NUMBER=$(gh pr view --json number -q .number 2>/dev/null) + fi + ``` + +2. **Route to Mode** + - If `PR_NUMBER` found → continue to **PR Mode Setup** + - If no `PR_NUMBER`: + - If `--language` provided → continue to **Standalone Mode Setup** + - Otherwise → error: "No PR detected. Use --pr=NUMBER or --language=CODE" + +### PR Mode Setup (Mode 1 & 2) + +3. **Determine Languages** + - If `--language=CODES` provided: Use those as filter (Mode 2) + - Otherwise: Extract all languages from PR (Mode 1) + + To extract languages from PR: + ```bash + gh api repos/{owner}/{repo}/pulls/{PR}/files --paginate -q '.[].filename' | \ + grep -E "(translations/[a-z]{2}(-[A-Z]{2})?/|intl/[a-z]{2}(-[A-Z]{2})?/)" | \ + sed 's|.*translations/||;s|.*intl/||' | cut -d'/' -f1 | sort -u + ``` + +4. **Determine File Scope** + - If `--scope=full`: Review ALL files for the determined languages + - If `--scope=pr` (default): Review ONLY files changed in the PR + + For `--scope=pr`, get the specific file list: + ```bash + gh api repos/{owner}/{repo}/pulls/{PR}/files --paginate -q '.[].filename' | \ + grep -E "(translations/|intl/)" | \ + grep -E "/(${LANGUAGES_REGEX})/" # If language filter applied + ``` + +5. **Report**: + - Mode 1: "Reviewing {N} files in PR #{NUMBER} ({LANGUAGES})" + - Mode 2: "Reviewing {N} {LANGUAGE} files in PR #{NUMBER}" + +### Standalone Mode Setup (Mode 3) + +3. **Set Languages** from `--language=CODES` + +4. **Set Scope** to `full` (review all files for those languages on `dev` branch) + +5. **Report**: "Reviewing all {LANGUAGE} files on dev branch" + +## Phase 1: Deploy Review Agents + +For EACH detected language, spawn a dedicated Task agent in parallel. + +Use a SINGLE message with MULTIPLE Task tool calls to achieve parallelism: + +``` +Task(subagent_type="general-purpose", description="Review LANG translations", prompt="...") +Task(subagent_type="general-purpose", description="Review LANG2 translations", prompt="...") +... +``` + +### Agent Prompt Template + +For each language agent, provide this prompt: + +``` +Review translation quality for {LANGUAGE_CODE} files. + +## Scope +{SCOPE_INSTRUCTION} + +## Files to Review +{LIST_OF_FILES_FOR_THIS_LANGUAGE} + +## Review Methodology + +**IMPORTANT: Reading Files from the PR Branch** +Do NOT checkout the PR branch directly - this will cause detached HEAD issues. Instead: +1. Create a worktree for the PR branch: + ```bash + PR_BRANCH=$(gh pr view {PR_NUMBER} --json headRefName -q .headRefName) + git worktree add .worktrees/pr-{PR_NUMBER} $PR_BRANCH + ``` +2. Read translation files from the worktree path: `.worktrees/pr-{PR_NUMBER}/public/content/translations/...` +3. Read English source files from the worktree: `.worktrees/pr-{PR_NUMBER}/public/content/...` + +This keeps your current branch clean while allowing full access to PR content. + +**For PR scope (`--scope=pr`):** +- Use `gh api repos/{owner}/{repo}/pulls/{PR}/files` to get the actual diff +- Focus on NEW or CHANGED content in the PR (not pre-existing content) +- Issues in unchanged lines are out of scope for this review +- Read both translation AND English source files from the worktree at `.worktrees/pr-{PR_NUMBER}/` + +**For full scope (`--scope=full` or `--language`):** +- Review the entire current content of each file +- Compare against English source files from the worktree: + - Markdown: `.worktrees/pr-{PR_NUMBER}/public/content/` (English originals) + - JSON: `.worktrees/pr-{PR_NUMBER}/src/intl/en/` (English namespace files) + +## Review Checklist + +### 1. Brand Names (CRITICAL - Must Fix) +These MUST remain in English - flag ANY translation: +- Programming languages: Solidity, Vyper, Rust, JavaScript, TypeScript, Python +- Companies/Products: Alchemy, Infura, MetaMask, Consensys, Chainlink, OpenZeppelin +- Protocols: Uniswap, Aave, Compound, MakerDAO +- Core terms: Ethereum, Bitcoin, Web3 + +For each file, search for these terms and verify they appear exactly as listed. + +### 2. Technical Terms (HIGH - Should Review) +These should use accepted local term OR remain English: +- Rollups, Layer 2/L2, Mainnet, Testnet, Sidechain, Beacon Chain +- Gas, Wei, Gwei, ETH (NEVER translate units) +- Staking, Slashing, Attestation, Validator +- Smart Contract, DApp, DeFi, NFT + +### 3. Tone/Register Consistency (MEDIUM) +Check if formal/informal address is consistent throughout: +- German: du vs. Sie +- French: tu vs. vous +- Japanese: casual vs. polite forms +- Spanish: tú vs. usted +- Other languages: appropriate formal/informal consistency + +### 4. Structural Issues +Review any sanitizer warnings for this language: +- Ambiguous href mismatches (multiple broken links in same paragraph) +- Block count differences from English +- Header structure anomalies + +### 5. Semantic Accuracy +Spot-check translations for meaning preservation: +- Does the translation convey the same meaning as English? +- Any significant drift or mistranslation? + +## Output Format + +Return a structured report: + +\`\`\` +## {LANGUAGE_CODE} Review Results + +### Critical Issues (Must Fix) +| File | Line | Issue | Current | Expected | +|------|------|-------|---------|----------| +| path/to/file.md | 45 | Brand translated | [local] | Solidity | + +### Warnings (Should Review) +| File | Line | Issue | Details | +|------|------|-------|---------| + +### Files Reviewed +- Total: N +- With issues: M +- Clean: N-M + +### Translation Quality Score + +Rate ONLY translation quality (not import artifacts like duplications, stray characters, or encoding issues): + +| Category | Score | Notes | +|----------|-------|-------| +| **Brand Name Preservation** | X/10 | Were brand names kept in English? | +| **Technical Accuracy** | X/10 | Were units (ETH, Gwei) and technical terms handled correctly? | +| **Semantic Fidelity** | X/10 | Does meaning match English source? | +| **Terminology Consistency** | X/10 | Is vocabulary consistent across files? | +| **Tone/Register** | X/10 | Is formal/informal address consistent? | + +**Overall: X.X/10** (average of above scores) + +Scoring guide: +- 10/10: Perfect, no issues +- 9/10: Excellent, minor issues only +- 8/10: Good, a few notable issues +- 7/10: Acceptable, several issues need attention +- 6/10 or below: Needs significant review + +### Summary +Brief assessment of overall translation quality for this language. +\`\`\` +``` + +### Model Selection + +Parse `--model=MODEL` from $ARGUMENTS (default: `opus`): +- `opus`: Deep analysis, thorough review of all checklist items +- `sonnet`: Balanced speed/depth, good for routine reviews +- `haiku`: Fast scan, focuses on brand names and critical issues only + +Pass the model parameter to Task agents: `model: "{MODEL}"` + +## Phase 2: Collect Results + +Wait for all language agents to complete. + +Aggregate results into a combined report: + +```markdown +# Translation Review Report + +**PR:** #{PR_NUMBER} +**Languages:** {LANG_LIST} ({COUNT} total) +**Files reviewed:** {TOTAL_FILES} +**Date:** {TODAY} + +## Summary by Language + +| Language | Files | Critical | Warnings | Quality Score | +|----------|-------|----------|----------|---------------| +| ar | 52 | 3 | 7 | 8.5/10 | +| de | 64 | 1 | 4 | 9.0/10 | +... + +## Quality Scores by Language + +### {LANGUAGE_CODE} - {OVERALL_SCORE}/10 + +| Category | Score | Notes | +|----------|-------|-------| +| Brand Name Preservation | X/10 | ... | +| Technical Accuracy | X/10 | ... | +| Semantic Fidelity | X/10 | ... | +| Terminology Consistency | X/10 | ... | +| Tone/Register | X/10 | ... | + +{SUMMARY} + +(Repeat for each language) + +## Critical Issues (Must Fix) + +### {LANGUAGE_CODE} +{CRITICAL_ISSUES_TABLE} + +## Warnings (Should Review) + +### {LANGUAGE_CODE} +{WARNINGS_TABLE} +``` + +## Phase 3: Present Results and Prompt User + +Use AskUserQuestion to present options: + +**Question:** "Review complete. Found X critical issues, Y warnings across N languages." + +**Options:** +1. **Post scores to PR** - Post quality scores as a comment on the PR +2. **Apply fixes** - Review and apply suggested brand name fixes with confirmation +3. **Export report** - Save to `translation-review-{PR_NUMBER}.md` +4. **Done** - End review session + +### If "Post scores to PR" selected: + +Generate a comment with all language scores and post it: + +```bash +gh pr comment {PR_NUMBER} --body "$(cat <<'EOF' +## 🌐 Translation Quality Review + +| Language | Files | Quality Score | Issues | +|----------|-------|---------------|--------| +| {LANG} | {N} | {SCORE}/10 | {CRITICAL} critical, {WARNINGS} warnings | +... + +
+📊 Detailed Scores: {LANGUAGE_CODE} + +| Category | Score | +|----------|-------| +| Brand Name Preservation | X/10 | +| Technical Accuracy | X/10 | +| Semantic Fidelity | X/10 | +| Terminology Consistency | X/10 | +| Tone/Register | X/10 | + +**Overall: X.X/10** + +{SUMMARY} + +
+ +(Repeat details block for each language) + +--- +*Reviewed by Claude Code* +EOF +)" +``` + +### If "Apply fixes" selected: + +**Worktree Isolation Check:** +Before applying any fixes, verify we're on the correct branch: + +```bash +CURRENT_BRANCH=$(git branch --show-current) +PR_BRANCH=$(gh pr view $PR_NUMBER --json headRefName -q .headRefName) +``` + +If `$CURRENT_BRANCH != $PR_BRANCH`: +1. Inform user: "Current branch '{CURRENT}' differs from PR branch '{PR_BRANCH}'" +2. Offer to create a worktree: + ```bash + git worktree add .worktrees/pr-$PR_NUMBER $PR_BRANCH + ``` +3. Apply fixes in the worktree, not the current directory +4. Report: "Fixes applied in worktree at .worktrees/pr-$PR_NUMBER" + +**Apply Fixes:** +For each critical issue (brand name translations): +1. Show the file, line, current value, and expected value +2. Ask: "Fix this? (Yes/No/Skip all remaining)" +3. If yes, use Edit tool to replace the translated term with the English original +4. Track all changes made + +After fixes applied, offer to commit changes with message: +`fix(i18n): correct brand name translations in {LANGUAGES}` + +## Protected Brand Names Reference + +These terms MUST NEVER be translated in any language: + +**Programming Languages:** +Solidity, Vyper, Rust, JavaScript, TypeScript, Python, Go, Java, C++ + +**Companies & Products:** +Alchemy, Infura, MetaMask, Consensys, Chainlink, OpenZeppelin, Gnosis, Flashbots + +**Protocols & Projects:** +Ethereum, Bitcoin, Uniswap, Aave, Compound, MakerDAO, Lido, Rocket Pool + +**Technical Units (NEVER translate):** +ETH, Wei, Gwei, Gas + +## Notes + +- This command runs AFTER the sanitizer (`post_import_sanitize.ts`) has processed files +- Sanitizer handles deterministic fixes; this handles judgment calls +- Large PRs (5+ languages) may take several minutes with Opus +- Use `--model=sonnet` or `--model=haiku` for faster reviews +- Consider running `/netlify-build-check` to look for broken Netlify builds, and identify MDX syntax errors diff --git a/.gitignore b/.gitignore index 7f2b60b0be7..bd0197d2f42 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,6 @@ storybook-static # Trigger .trigger + +# Git worktrees for Claude commands +.worktrees