diff --git a/.agents/skills/pr-description/SKILL.md b/.agents/skills/pr-description/SKILL.md index f9b0fac9c..c6486c782 100644 --- a/.agents/skills/pr-description/SKILL.md +++ b/.agents/skills/pr-description/SKILL.md @@ -62,6 +62,16 @@ Write 1-3 concise sentences explaining the reason for the change. Tie it to the Name affected screens, flows, platforms, users, modules, or developer workflows. Use a short sentence or compact bullets. If impact is unclear, leave a placeholder comment instead of guessing. +### Risk Classification + +Add the appropriate `risk:*` label when the PR is opened. If the label is unknown, escalate instead of guessing. + +- `risk:low` for config, copy, or minor UI tweaks with low blast radius. +- `risk:medium` for feature work or refactors touching multiple files. +- `risk:high` for auth, payments, migrations, or security-sensitive code. + +If the branch or user request does not make the risk obvious, leave the template placeholder and call out the uncertainty in Notes. + ### How did you test this? List commands run and manual checks performed. Keep the existing checklist from the template and check only items that are supported by evidence or explicitly provided by the user. diff --git a/.agents/skills/review-changes/SKILL.md b/.agents/skills/review-changes/SKILL.md index 3130a8276..44f18e3fd 100644 --- a/.agents/skills/review-changes/SKILL.md +++ b/.agents/skills/review-changes/SKILL.md @@ -56,16 +56,49 @@ Perform a code review of the current branch diff against the project's architect ## Output Format -Group findings by REVIEW.md category. For each finding: +Start with an overall classification, then list findings grouped by REVIEW.md category. + +### Required Labels + +Every finding must start with exactly one label: +- `ai:clean` — no significant issues found. +- `ai:minor` — style/readability/maintainability/convention issues unlikely to cause bugs. +- `ai:serious` — logic/security/correctness/reliability issues that should block merge. + +Overall review classification must use the highest severity found: +- If any finding is `ai:serious`, overall is `ai:serious`. +- Else if any finding is `ai:minor`, overall is `ai:minor`. +- Else overall is `ai:clean`. + +### Report Structure + +1. Overall summary block: ``` -**[Category]** `path/to/file.ts` — short description of the issue and what the correct approach is. +Overall Review: ai: + +Summary: +- +- ``` -If a category has no issues, skip it. +2. Findings grouped by category. For each finding: -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. +``` +ai: **[Category]** `path/to/file.ts:line` — short description of the issue and what the correct approach is. +``` + +If a category has no findings, skip it. + +If no issues are found, output a single clean finding plus a clean overall summary: + +``` +Overall Review: ai:clean + +Summary: +- No significant issues found. + +ai:clean Review passed with no actionable findings. +``` 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/.claude/skills/review-changes/SKILL.md b/.claude/skills/review-changes/SKILL.md index 3130a8276..44f18e3fd 100644 --- a/.claude/skills/review-changes/SKILL.md +++ b/.claude/skills/review-changes/SKILL.md @@ -56,16 +56,49 @@ Perform a code review of the current branch diff against the project's architect ## Output Format -Group findings by REVIEW.md category. For each finding: +Start with an overall classification, then list findings grouped by REVIEW.md category. + +### Required Labels + +Every finding must start with exactly one label: +- `ai:clean` — no significant issues found. +- `ai:minor` — style/readability/maintainability/convention issues unlikely to cause bugs. +- `ai:serious` — logic/security/correctness/reliability issues that should block merge. + +Overall review classification must use the highest severity found: +- If any finding is `ai:serious`, overall is `ai:serious`. +- Else if any finding is `ai:minor`, overall is `ai:minor`. +- Else overall is `ai:clean`. + +### Report Structure + +1. Overall summary block: ``` -**[Category]** `path/to/file.ts` — short description of the issue and what the correct approach is. +Overall Review: ai: + +Summary: +- +- ``` -If a category has no issues, skip it. +2. Findings grouped by category. For each finding: -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. +``` +ai: **[Category]** `path/to/file.ts:line` — short description of the issue and what the correct approach is. +``` + +If a category has no findings, skip it. + +If no issues are found, output a single clean finding plus a clean overall summary: + +``` +Overall Review: ai:clean + +Summary: +- No significant issues found. + +ai:clean Review passed with no actionable findings. +``` 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/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a0878d3de..bfe6fc5da 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -35,6 +35,25 @@ _**Why** did you make these changes? This is your opportunity to provide the rat _Does your code affect something downstream? Are there side effects people should know about? Tag any developers that should be kept abreast of this change._ --> +--- + +### Layer 2: Risk Classification + +Author applies a risk label when opening the PR. When in doubt, escalate. + +| Label | When to use | +| --- | --- | +| `risk:low` | Config, copy, minor UI tweaks. Low blast radius. | +| `risk:medium` | Feature work, refactors touching multiple files. | +| `risk:high` | Auth, payments, migrations, security-sensitive code. | + +**Setup** + +- [ ] Create `risk:low`, `risk:medium`, `risk:high` labels in the repo +- [ ] Add risk criteria to contributing guide or PR template +- [ ] Add reminder in PR template to apply the label before requesting review +- [ ] Define who can override/escalate (suggested: tech lead) + ## How did you test this? ## 💎 Libraries used diff --git a/cli/clone-repo.js b/cli/clone-repo.js index 269d4e0a2..e9daa0a07 100755 --- a/cli/clone-repo.js +++ b/cli/clone-repo.js @@ -1,4 +1,8 @@ -const { runCommand, TEMPLATE_REPOSITORY } = require('./utils.js'); +const { + runCommand, + TEMPLATE_REPOSITORY, + escapeShellArg, +} = require('./utils.js'); const { consola } = require('consola'); const getLatestRelease = async () => { @@ -23,7 +27,9 @@ const cloneLatestTemplateRelease = async (projectName) => { consola.info(`Using Rootstrap's Template ${latestRelease}`); // create a new project based on Rootstrap template - const cloneStarter = `git clone -b ${latestRelease} --depth=1 https://github.com/${TEMPLATE_REPOSITORY}.git ${projectName}`; + const escapedLatestRelease = escapeShellArg(latestRelease); + const escapedProjectName = escapeShellArg(projectName); + const cloneStarter = `git clone -b ${escapedLatestRelease} --depth=1 https://github.com/${TEMPLATE_REPOSITORY}.git ${escapedProjectName}`; await runCommand(cloneStarter, { loading: 'Extracting the template...', success: 'Template extracted successfully', diff --git a/cli/index.js b/cli/index.js index 2d3bd1d36..35f2bc4c0 100755 --- a/cli/index.js +++ b/cli/index.js @@ -3,7 +3,11 @@ const { consola } = require('consola'); const { showMoreDetails } = require('./utils.js'); const { cloneLatestTemplateRelease } = require('./clone-repo.js'); -const { setupProject, installDependencies } = require('./setup-project.js'); +const { + setupProject, + installDependencies, + installPushgate, +} = require('./setup-project.js'); const pkg = require('./package.json'); const { name: packageName } = pkg; @@ -27,6 +31,9 @@ const createRootstrapApp = async () => { // install project dependencies using pnpm await installDependencies(projectName); + // install Pushgate hook (best-effort) + await installPushgate(projectName); + // show instructions to run the project + link to the documentation showMoreDetails(projectName); }; diff --git a/cli/setup-project.js b/cli/setup-project.js index cbde3776b..e4b6f42ab 100755 --- a/cli/setup-project.js +++ b/cli/setup-project.js @@ -1,8 +1,7 @@ const { execShellCommand, runCommand, - UPSTREAM_REPOSITORY, - TEMPLATE_REPOSITORY, + escapeShellArg, } = require('./utils.js'); const { consola } = require('consola'); const fs = require('fs-extra'); @@ -14,17 +13,34 @@ const ProjectFilesManager = require('./project-files-manager.js'); let projectFilesManager; const initializeProjectRepository = async (projectName) => { - await execShellCommand(`cd ${projectName} && git init && cd ..`); + const escapedProjectName = escapeShellArg(projectName); + await execShellCommand(`cd ${escapedProjectName} && git init && cd ..`); }; const installDependencies = async (projectName) => { - await runCommand(`cd ${projectName} && pnpm install`, { + const escapedProjectName = escapeShellArg(projectName); + await runCommand(`cd ${escapedProjectName} && pnpm install`, { loading: 'Installing project dependencies', success: 'Dependencies installed', error: 'Failed to install dependencies, Make sure you have pnpm installed', }); }; +const installPushgate = async (projectName) => { + consola.start('Installing Pushgate pre-push hook'); + try { + const escapedProjectName = escapeShellArg(projectName); + await execShellCommand( + `cd ${escapedProjectName} && curl -fsSL https://raw.githubusercontent.com/rootstrap/ai-pushgate/main/install.sh | bash` + ); + consola.success('Pushgate pre-push hook installed'); + } catch (error) { + consola.warn( + 'Could not auto-install Pushgate. Run installer manually from the project root.' + ); + } +}; + const removeUnrelatedFiles = () => { projectFilesManager.removeFiles([ '.git', @@ -227,4 +243,5 @@ const setupProject = async (projectName) => { module.exports = { setupProject, installDependencies, + installPushgate, }; diff --git a/cli/utils.js b/cli/utils.js index 7bbcb5e1d..d72704b4a 100755 --- a/cli/utils.js +++ b/cli/utils.js @@ -5,6 +5,10 @@ const { consola } = require('consola'); const UPSTREAM_REPOSITORY = "obytes/react-native-template-obytes"; const TEMPLATE_REPOSITORY = "rootstrap/react-native-template"; +const escapeShellArg = (value) => { + return `'${String(value).replaceAll(/'/g, "'\\''")}'`; +}; + const execShellCommand = (cmd) => { return new Promise((resolve, reject) => { exec(cmd, (error, stdout, stderr) => { @@ -46,6 +50,7 @@ module.exports = { runCommand, showMoreDetails, execShellCommand, + escapeShellArg, UPSTREAM_REPOSITORY, TEMPLATE_REPOSITORY, };