From dddace74ec4cd7e431b434baccac4ba5567731fc Mon Sep 17 00:00:00 2001 From: Adam Creeger Date: Thu, 5 Feb 2026 00:53:02 -0500 Subject: [PATCH] feat(issue-553): improve draft PR body with issue context and Fixes keyword - Make PRManager.issuePrefix public for LoomManager access - Draft PR body now includes issue title, body, and uses Fixes keyword - Uses configured issue prefix instead of hardcoded # - Update tests for new draft PR body format --- .iloom/settings.json | 2 +- src/lib/LoomManager.test.ts | 7 ++++++- src/lib/LoomManager.ts | 10 +++++++--- src/lib/PRManager.ts | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.iloom/settings.json b/.iloom/settings.json index 5ac9307..bd57437 100644 --- a/.iloom/settings.json +++ b/.iloom/settings.json @@ -12,7 +12,7 @@ "agents": { "iloom-issue-analyzer": { "model": "opus" }, "iloom-issue-planner": { "model": "opus", "review": true }, - "iloom-issue-analyze-and-plan": { "model": "opus" }, + "iloom-issue-analyze-and-plan": { "model": "opus", "review": true }, "iloom-issue-implementer": { "model": "opus" }, "iloom-code-reviewer": { "providers": { "gemini": "gemini-3-pro-preview" } }, "iloom-artifact-reviewer": { "enabled": true, "providers": { "gemini": "gemini-3-pro-preview" } } diff --git a/src/lib/LoomManager.test.ts b/src/lib/LoomManager.test.ts index dc0dc6f..ed2e471 100644 --- a/src/lib/LoomManager.test.ts +++ b/src/lib/LoomManager.test.ts @@ -118,6 +118,7 @@ vi.mock('./LoomLauncher.js', () => ({ // Shared mock functions for verification in tests const mockCreateDraftPR = vi.fn() const mockCheckForExistingPR = vi.fn() +let mockIssuePrefix = '#' vi.mock('./PRManager.js', () => { // Use a class-like factory that creates fresh instances // This avoids issues with mockReset clearing the constructor implementation @@ -125,6 +126,7 @@ vi.mock('./PRManager.js', () => { PRManager: class MockPRManager { createDraftPR = mockCreateDraftPR checkForExistingPR = mockCheckForExistingPR + get issuePrefix() { return mockIssuePrefix } }, } }) @@ -146,6 +148,7 @@ describe('LoomManager', () => { let mockSettings: vi.Mocked beforeEach(() => { + mockIssuePrefix = '#' // Reset to GitHub default mockGitWorktree = new GitWorktreeManager() as vi.Mocked mockGitHub = new GitHubService() as vi.Mocked mockBranchNaming = new DefaultBranchNamingService() as vi.Mocked @@ -492,6 +495,7 @@ describe('LoomManager', () => { // Configure Linear provider (doesn't support PRs natively) mockGitHub.supportsPullRequests = false mockGitHub.providerName = 'linear' + mockIssuePrefix = '' // Linear issues use empty prefix (identifier already includes team key) // Mock settings with github-draft-pr mode // (Issue #464: Linear + github-draft-pr should work since PRs go through GitHub CLI) @@ -527,10 +531,11 @@ describe('LoomManager', () => { expect(result.type).toBe('issue') // Verify draft PR was created via PRManager (not Linear's issue tracker) + // Linear identifier is 123 with empty prefix, so body contains "Fixes 123" expect(mockCreateDraftPR).toHaveBeenCalledWith( expect.any(String), // branch name 'Test Linear Issue', // PR title from issue - expect.stringContaining('PR for issue'), // PR body + expect.stringContaining('Fixes 123'), // PR body with Fixes keyword (no prefix for Linear) expectedPath // worktree path ) diff --git a/src/lib/LoomManager.ts b/src/lib/LoomManager.ts index ddafcc6..7870499 100644 --- a/src/lib/LoomManager.ts +++ b/src/lib/LoomManager.ts @@ -276,9 +276,13 @@ export class LoomManager { // For issue mode: use issue title and reference issue number // For branch mode: use branch name and generic description const prTitle = issueData?.title ?? `Work on ${branchName}` - const prBody = input.type === 'issue' - ? `PR for issue #${input.identifier}\n\nThis PR was created automatically by iloom.` - : `Branch: ${branchName}\n\nThis PR was created automatically by iloom.` + let prBody: string + if (input.type === 'issue') { + const issueBody = issueData?.body ? `\n\n## ${issueData.title}\n\n${issueData.body}` : '' + prBody = `Fixes ${prManager.issuePrefix}${input.identifier}${issueBody}\n\n---\n*This PR was created automatically by iloom.*` + } else { + prBody = `Branch: ${branchName}\n\n---\n*This PR was created automatically by iloom.*` + } // Create draft PR getLogger().info('Creating draft PR...') diff --git a/src/lib/PRManager.ts b/src/lib/PRManager.ts index 2309d4d..7ad9101 100644 --- a/src/lib/PRManager.ts +++ b/src/lib/PRManager.ts @@ -25,7 +25,7 @@ export class PRManager { /** * Get the issue prefix from the configured provider */ - private get issuePrefix(): string { + public get issuePrefix(): string { const providerType = this.settings.issueManagement?.provider ?? 'github' const provider = IssueManagementProviderFactory.create(providerType) return provider.issuePrefix