import { tool } from "@opencode-ai/plugin" import { runGh, formatResult } from "./_shared" const TITLE_REGEX = /^(feat|fix|chore|docs|refactor|test|style|perf)\([^)]+\): .{1,72}$/ const CYRILLIC = /[\u0400-\u04FF]/ const RULES = `Rules: - Title: type(scope): description (<=72 chars description) - Types: feat, fix, chore, docs, refactor, test, style, perf - Scope is mandatory - Title in English only - Body must contain '## Что сделано' heading - Body must contain '## Почему' heading - Body must contain '## Watch out' heading - Body must contain '## Pending' heading - Body in Russian (must contain Cyrillic)` export default tool({ description: "Create a GitHub PR with title/body validation. Validates: title format type(scope): description (<=72), English title, body headings (## Что сделано, ## Почему, ## Watch out, ## Pending), body in Russian. If issue_number provided, appends 'Closes #N' to body. Returns PR URL on success.", args: { title: tool.schema.string().describe("PR title (conventional format: type(scope): description)"), body: tool.schema.string().describe("PR body in Russian with ## Что сделано, ## Почему, ## Watch out and ## Pending headings"), issue_number: tool.schema.number().optional().describe("Issue number to link (appends 'Closes #N' to body)"), repo: tool.schema.string().optional().describe("Optional repo (owner/name). If omitted, gh auto-detects from context.worktree."), }, async execute(args, context) { const title = args.title let body = args.body if (!TITLE_REGEX.test(title)) { return `❌ PR title must match format: type(scope): description\n\n${RULES}` } if (CYRILLIC.test(title)) { return `❌ PR title must be in English\n\n${RULES}` } if (!body.includes("## Что сделано")) { return `❌ PR body must contain '## Что сделано' heading\n\n${RULES}` } if (!body.includes("## Почему")) { return `❌ PR body must contain '## Почему' heading\n\n${RULES}` } if (!body.includes("## Watch out")) { return `❌ PR body must contain '## Watch out' heading\n\n${RULES}` } if (!body.includes("## Pending")) { return `❌ PR body must contain '## Pending' heading\n\n${RULES}` } if (!CYRILLIC.test(body)) { return `❌ PR body must be in Russian\n\n${RULES}` } if (args.issue_number) { body = body + "\n\nCloses #" + args.issue_number } const r = await runGh(["pr", "create", "--title", title, "--body", body], args.repo, { cwd: context.worktree }) if (r.status !== 0) { return formatResult(r, "gh pr create") } return `PR created: ${r.stdout.trim()}` }, })