UNPKG

miyabi-agent-sdk

Version:

Miyabi Autonomous Agent SDK - 7 Agents based on Shikigaku Theory with 100% cost reduction mode

256 lines (247 loc) 8.16 kB
/** * PRAgent - PR作成Agent * * 識学理論適用: * - 責任: Draft Pull Requestを作成 * - 権限: ブランチ作成、PR作成(Draft)、ラベル付与 * - 階層: Specialist Layer * * Phase 8-2: Real API Integration */ import { GitHubClient } from "../clients/GitHubClient.js"; /** * PRAgent実装 * * Branch作成 → Files commit → Draft PR作成 → PR本文生成 */ export class PRAgent { githubClient; constructor(config) { if (config?.githubToken) { this.githubClient = new GitHubClient(config.githubToken); } } /** * メイン実行ロジック */ async create(input) { try { const githubClient = input.githubClient || this.githubClient; const baseBranch = input.baseBranch || "main"; // 1. Feature branch名生成 const branchName = this.generateBranchName(input.issueNumber); // 2. Branch作成(GitHub API) await this.createBranch(input.owner, input.repository, branchName, baseBranch, githubClient); // 3. Files commit await this.commitFiles(input.owner, input.repository, branchName, input.files, this.generateCommitMessage(input), githubClient); // 4. Draft PR作成 const pr = await this.createPullRequest({ owner: input.owner, repository: input.repository, base: baseBranch, head: branchName, title: this.generatePRTitle(input), body: this.generatePRBody(input), draft: true, githubClient, }); return { success: true, data: pr, }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : "Unknown error occurred", }; } } /** * Branch名生成 */ generateBranchName(issueNumber) { const timestamp = Date.now(); return `agent/issue-${issueNumber}-${timestamp}`; } /** * Branch作成 * * Phase 8-2: Real GitHub API integration */ async createBranch(owner, repository, branchName, baseBranch, githubClient) { if (githubClient) { // Real API implementation await githubClient.createBranch(owner, repository, branchName, baseBranch); console.log(`[PRAgent] Created branch: ${branchName} from ${baseBranch}`); } else { // Mock implementation (fallback) console.log(`[PRAgent] Would create branch: ${branchName} from ${baseBranch}`); } } /** * Files commit * * Phase 8-2: Real GitHub API integration */ async commitFiles(owner, repository, branch, files, message, githubClient) { if (githubClient) { // Real API implementation await githubClient.commitFiles({ owner, repo: repository, branch, files: files.map(f => ({ path: f.path, content: f.content })), message, }); console.log(`[PRAgent] Committed ${files.length} files to ${branch}`); } else { // Mock implementation (fallback) console.log(`[PRAgent] Would commit ${files.length} files to ${branch}:`, message); } } /** * Commit message生成(Conventional Commits準拠) */ generateCommitMessage(input) { // Conventional Commits形式 // type(scope): subject // // body // // footer const type = this.inferCommitType(input.files); const scope = this.inferScope(input.files); const subject = `autonomous implementation for issue #${input.issueNumber}`; const body = ` Quality Score: ${input.qualityReport.qualityScore}/100 Coverage: ${input.qualityReport.coverage}% Files changed: ${input.files.length} `.trim(); const footer = ` Closes #${input.issueNumber} 🤖 Generated by Miyabi Autonomous Agent `.trim(); return `${type}${scope ? `(${scope})` : ""}: ${subject}\n\n${body}\n\n${footer}`; } /** * Commit type推論(Conventional Commits) */ inferCommitType(files) { const actions = files.map((f) => f.action); if (actions.includes("delete")) return "refactor"; if (actions.every((a) => a === "create")) return "feat"; if (actions.some((a) => a === "modify")) return "fix"; return "feat"; } /** * Scope推論(ファイルパスから) */ inferScope(files) { // 最初のファイルのディレクトリをscopeとする if (files.length === 0) return ""; const firstFile = files[0].path; const parts = firstFile.split("/"); // src/agents/Foo.ts → "agents" if (parts.length > 1 && parts[0] === "src") { return parts[1]; } return parts[0]; } /** * PR title生成 */ generatePRTitle(input) { const type = this.inferCommitType(input.files); return `${type}: autonomous implementation for issue #${input.issueNumber}`; } /** * PR本文生成 */ generatePRBody(input) { const passedEmoji = input.qualityReport.passed ? "✅" : "❌"; return ` ## 🤖 Autonomous Agent Implementation **Issue**: #${input.issueNumber} **Quality Score**: ${input.qualityReport.qualityScore}/100 **Coverage**: ${input.qualityReport.coverage}% ### Quality Report ${passedEmoji} Quality check ${input.qualityReport.passed ? "passed" : "failed"} ${input.qualityReport.issues.length > 0 ? ` ### Issues Found ${input.qualityReport.issues .map((issue) => `- [${issue.severity}] ${issue.file}${issue.line ? `:${issue.line}` : ""} - ${issue.message}`) .join("\n")} ` : ""} ${input.qualityReport.suggestions.length > 0 ? ` ### Suggestions ${input.qualityReport.suggestions.map((s) => `- ${s}`).join("\n")} ` : ""} ### Files Changed ${input.files.map((f) => `- [${f.action}] \`${f.path}\``).join("\n")} ### Checklist - [x] Code generated - [x] Tests generated - [x] Quality check (≥80): ${input.qualityReport.qualityScore}/100 - [ ] Manual review required - [ ] Ready to merge Closes #${input.issueNumber} --- 🤖 Generated by Miyabi Autonomous Agent `.trim(); } /** * Pull Request作成 * * Phase 8-2: Real GitHub API integration */ async createPullRequest(params) { if (params.githubClient) { // Real API implementation const prInfo = await params.githubClient.createPullRequest({ owner: params.owner, repo: params.repository, title: params.title, body: params.body, head: params.head, base: params.base, draft: params.draft, }); console.log(`[PRAgent] Created PR #${prInfo.number}: ${prInfo.html_url}`); return { number: prInfo.number, url: prInfo.html_url, branch: params.head, status: params.draft ? "draft" : "open", }; } else { // Mock implementation (fallback) const mockPrNumber = Math.floor(Math.random() * 1000) + 1; const mockPrUrl = `https://github.com/${params.owner}/${params.repository}/pull/${mockPrNumber}`; console.log(`[PRAgent] Would create PR:`, { title: params.title, base: params.base, head: params.head, draft: params.draft, }); return { number: mockPrNumber, url: mockPrUrl, branch: params.head, status: "draft", }; } } } //# sourceMappingURL=PRAgent.js.map