diff --git a/.claude/skills/review-changes/SKILL.md b/.claude/skills/review-changes/SKILL.md deleted file mode 100644 index 3130a8276..000000000 --- a/.claude/skills/review-changes/SKILL.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -name: review-changes -description: Reviews the current branch diff against this project's architecture, conventions, and code review checklist. Use when the user asks to "review my changes", "review the diff", "check my code", "run a code review", or "review this branch". -allowed-tools: Bash(git:*), Read ---- - -# Review Changes - -## Purpose - -Perform a code review of the current branch diff against the project's architecture rules, coding conventions, and the REVIEW.md checklist. Report findings grouped by category, with file and line references where possible. - -## Workflow - -1. Read the project rules: - - `AGENTS.md` — critical constraints and glossary - - `REVIEW.md` — the review checklist; this is the primary source of truth for what to flag - - `agent_docs/architecture.md` — layer diagram, routing conventions, dual auth system - - `agent_docs/conventions.md` — API hooks, styling, forms, i18n, anti-patterns - -2. Inspect the branch diff: - - Run `git fetch origin master`. - - Run `git log origin/master..HEAD --oneline` to understand the commit scope. - - Run `git diff origin/master...HEAD --stat` to see which files changed. - - Run `git diff origin/master...HEAD` to read the full diff. - -3. If a changed file needs more context to review correctly (e.g. to check imports, types, or hook usage), use Read to open it. - -4. Review the diff against every category in REVIEW.md: - - API & Query layer - - Auth & security - - Type safety - - i18n - - Styling - - Testing - - Performance - -5. Also check for violations of the critical constraints in `AGENTS.md`: - - Package manager (`pnpm` only) - - Env values via `Env` from `@/lib/env` - - No auth logic in screen components - - No manual camelCase↔snake_case conversion - - No direct MMKV access in components - - All strings through `useTranslation()` - - `createMutation` / `createQuery` from `react-query-kit` - - `createQueryKeys` in `src/api/query-factory.ts` - - `@shopify/flash-list` for growable lists - - `expo-crypto` for random IDs - - `react-hook-form` + `zod` for forms - - `moti` or `react-native-reanimated` for animations (no `Animated` from RN directly) - -6. Check layer boundaries from `agent_docs/architecture.md`: - - Data flows down: `app/ → components/ → api/ → lib/` - - Route guards belong only in `src/app/_layout.tsx`, never in screen files - - Auth state management belongs only in `src/components/providers/auth.tsx` and `src/lib/auth/index.tsx` - -## Output Format - -Group findings by REVIEW.md category. For each finding: - -``` -**[Category]** `path/to/file.ts` — short description of the issue and what the correct approach is. -``` - -If a category has no issues, skip it. - -End the report with one of: -- **No issues found** — if the diff is clean across all categories. -- **X issue(s) found** — a one-line summary count. - -Do not suggest stylistic preferences not grounded in REVIEW.md, AGENTS.md, or agent_docs/. Do not flag things that are already handled automatically by the interceptors or tooling (e.g. case conversion, token injection). diff --git a/.gitignore b/.gitignore index c471eaa12..45e0e8ab2 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ cli/README.md # PR description scratchpad (agents) PR_DESCRIPTION.md + +# PR review triage scratchpad (agents) +PR_REVIEW_TRIAGE.md diff --git a/cli/index.js b/cli/index.js index 2d3bd1d36..ee16543a1 100755 --- a/cli/index.js +++ b/cli/index.js @@ -4,6 +4,7 @@ const { consola } = require('consola'); const { showMoreDetails } = require('./utils.js'); const { cloneLatestTemplateRelease } = require('./clone-repo.js'); const { setupProject, installDependencies } = require('./setup-project.js'); +const { installClaudeToolkit } = require('./install-claude-plugin.js'); const pkg = require('./package.json'); const { name: packageName } = pkg; @@ -27,6 +28,9 @@ const createRootstrapApp = async () => { // install project dependencies using pnpm await installDependencies(projectName); + // install the Rootstrap rn-toolkit Claude Code plugin + await installClaudeToolkit(projectName); + // show instructions to run the project + link to the documentation showMoreDetails(projectName); }; diff --git a/cli/install-claude-plugin.js b/cli/install-claude-plugin.js new file mode 100644 index 000000000..e05125835 --- /dev/null +++ b/cli/install-claude-plugin.js @@ -0,0 +1,65 @@ +const { execFile } = require('node:child_process'); +const { consola } = require('consola'); + +const MARKETPLACE_REPOSITORY = 'rootstrap/rn-claude-toolkit'; +const MARKETPLACE_NAME = 'rootstrap'; +const PLUGIN_NAME = 'rn-toolkit'; + +const MANUAL_INSTALL_HINT = + `claude plugin marketplace add ${MARKETPLACE_REPOSITORY} --scope project && ` + + `claude plugin install ${PLUGIN_NAME}@${MARKETPLACE_NAME} --scope project`; + +// Quiet variant of execShellCommand: no shell interpreter, and failures here are expected and handled +const runClaude = (args, options) => + new Promise((resolve, reject) => { + execFile('claude', args, options, (error, stdout, stderr) => { + if (error) { + reject(error); + return; + } + resolve(stdout || stderr); + }); + }); + +const isClaudeCodeAvailable = async () => { + try { + await runClaude(['--version']); + return true; + } catch { + return false; + } +}; + +const installClaudeToolkit = async (projectName) => { + if (!(await isClaudeCodeAvailable())) { + consola.info( + `Claude Code CLI not found, skipping ${PLUGIN_NAME} plugin installation.\n` + + ` Install it later from the project root with: ${MANUAL_INSTALL_HINT}` + ); + return; + } + + consola.start(`Installing the ${PLUGIN_NAME} Claude Code plugin 🤖`); + try { + const options = { cwd: projectName }; + await runClaude( + ['plugin', 'marketplace', 'add', MARKETPLACE_REPOSITORY, '--scope', 'project'], + options + ); + await runClaude( + ['plugin', 'install', `${PLUGIN_NAME}@${MARKETPLACE_NAME}`, '--scope', 'project'], + options + ); + consola.success(`${PLUGIN_NAME} plugin installed`); + } catch { + consola.warn( + `Could not install the ${PLUGIN_NAME} plugin. The marketplace repository is private, ` + + `so you need git access to ${MARKETPLACE_REPOSITORY} as a member of the Rootstrap org.\n` + + ` Retry from the project root with: ${MANUAL_INSTALL_HINT}` + ); + } +}; + +module.exports = { + installClaudeToolkit, +};