Files
gai/src/prompt.ts
T
Mplan 6ff541284e feat(cli): add pull request creation with AI-generated messages (#2)
Add a new `gai pr` subcommand that generates pull request titles and descriptions using AI, then creates the PR via GitHub CLI (`gh`) or Gitea CLI (`tea`). This extends the existing commit-generation system by reusing retry logic and prompt infrastructure, and introduces a `callAI` function that returns raw output (instead of pre-cleaned messages) to support structured PR responses.

Reviewed-on: #2
2026-06-11 00:39:20 +08:00

119 lines
3.6 KiB
TypeScript

import type { PRContext, ProjectContext } from "./types";
export const SYSTEM_PROMPT = `You are an expert at writing concise, meaningful git commit messages following the Conventional Commits specification.
Format: <type>(<scope>): <description>
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
Rules:
1. Use imperative mood in description (e.g., "add feature" not "added feature")
2. Keep the first line (subject) under 72 characters
3. Scope is optional but recommended when the change area is clear
4. For breaking changes, add "!" after the scope: feat(scope)!: description
5. If the change needs explanation, add a body separated by a blank line — explain WHY, not WHAT
6. Match the language and style of recent commits if provided
7. Be specific — avoid vague messages like "update code" or "fix bugs"
8. Output ONLY the commit message text, no markdown, no code blocks, no prefixes`;
export function buildPrompt(context: ProjectContext): string {
const parts: string[] = [];
if (
context.packageDescription ||
context.readme ||
context.structure
) {
parts.push("## Project Context");
if (context.packageDescription) {
parts.push(`Description: ${context.packageDescription}`);
}
if (context.structure) {
parts.push(`Structure: ${context.structure}`);
}
if (context.readme) {
parts.push(`README:\n${context.readme}`);
}
parts.push("");
}
if (context.recentCommits.length > 0) {
parts.push("## Recent Commits (for style reference)");
for (const c of context.recentCommits) {
parts.push(c);
}
parts.push("");
}
parts.push("## Staged Changes");
parts.push("```diff");
parts.push(context.diff);
parts.push("```");
parts.push("");
parts.push("Generate a commit message for the above changes.");
return parts.join("\n");
}
export const PR_SYSTEM_PROMPT = `You are an expert at writing clear, concise pull request titles and descriptions.
Format:
<pr title>
<blank line>
<pr body>
Rules:
1. Title must be under 72 characters, in imperative mood
2. Follow the Conventional Commits style for the title (e.g., "feat(api): add user authentication")
3. Body should be 2-3 sentences in plain text explaining WHAT was changed and WHY
4. Be specific — avoid vague messages
5. Match the language and style of recent commits if provided
6. If the branch name hints at the type (e.g., "feat/..." or "fix/..."), reflect that in the title
7. Output ONLY the PR text — no markdown, no code blocks, no prefixes`;
export function buildPRPrompt(context: PRContext): string {
const parts: string[] = [];
if (
context.packageDescription ||
context.readme ||
context.structure
) {
parts.push("## Project Context");
if (context.packageDescription) {
parts.push(`Description: ${context.packageDescription}`);
}
if (context.structure) {
parts.push(`Structure: ${context.structure}`);
}
if (context.readme) {
parts.push(`README:\n${context.readme}`);
}
parts.push("");
}
parts.push("## Branch Info");
parts.push(`Branch: ${context.branchName}`);
parts.push(`Target base: ${context.baseBranch}`);
parts.push("");
if (context.branchCommits.length > 0) {
parts.push("## Commits on This Branch");
for (const c of context.branchCommits) {
parts.push(c);
}
parts.push("");
}
parts.push("## Changes (diff from base)");
parts.push("```diff");
parts.push(context.diff);
parts.push("```");
parts.push("");
parts.push(
"Generate a pull request title and brief body for the above changes.",
);
return parts.join("\n");
}