edsger 0.21.1 ā 0.21.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/phases/code-implementation/branch-pr-creator.js +16 -2
- package/dist/phases/code-implementation/index.js +26 -2
- package/dist/phases/code-refine-verification/llm-analyzer.d.ts +1 -1
- package/dist/phases/code-refine-verification/llm-analyzer.js +12 -11
- package/dist/phases/code-refine-verification/prompts.d.ts +1 -1
- package/dist/phases/code-refine-verification/prompts.js +75 -35
- package/dist/phases/pull-request/creator.js +17 -2
- package/package.json +1 -1
- package/.claude/settings.local.json +0 -28
- package/.env.local +0 -12
- package/dist/api/features/__tests__/regression-prevention.test.d.ts +0 -5
- package/dist/api/features/__tests__/regression-prevention.test.js +0 -338
- package/dist/api/features/__tests__/status-updater.integration.test.d.ts +0 -5
- package/dist/api/features/__tests__/status-updater.integration.test.js +0 -497
- package/dist/commands/workflow/pipeline-runner.d.ts +0 -17
- package/dist/commands/workflow/pipeline-runner.js +0 -393
- package/dist/commands/workflow/runner.d.ts +0 -26
- package/dist/commands/workflow/runner.js +0 -119
- package/dist/commands/workflow/workflow-runner.d.ts +0 -26
- package/dist/commands/workflow/workflow-runner.js +0 -119
- package/dist/phases/code-implementation/analyzer-helpers.d.ts +0 -28
- package/dist/phases/code-implementation/analyzer-helpers.js +0 -177
- package/dist/phases/code-implementation/analyzer.d.ts +0 -32
- package/dist/phases/code-implementation/analyzer.js +0 -629
- package/dist/phases/code-implementation/context-fetcher.d.ts +0 -17
- package/dist/phases/code-implementation/context-fetcher.js +0 -86
- package/dist/phases/code-implementation/mcp-server.d.ts +0 -1
- package/dist/phases/code-implementation/mcp-server.js +0 -93
- package/dist/phases/code-implementation/prompts-improvement.d.ts +0 -5
- package/dist/phases/code-implementation/prompts-improvement.js +0 -108
- package/dist/phases/code-implementation-verification/verifier.d.ts +0 -31
- package/dist/phases/code-implementation-verification/verifier.js +0 -196
- package/dist/phases/code-refine/analyzer.d.ts +0 -41
- package/dist/phases/code-refine/analyzer.js +0 -561
- package/dist/phases/code-refine/context-fetcher.d.ts +0 -94
- package/dist/phases/code-refine/context-fetcher.js +0 -423
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.d.ts +0 -22
- package/dist/phases/code-refine-verification/analysis/llm-analyzer.js +0 -134
- package/dist/phases/code-refine-verification/verifier.d.ts +0 -47
- package/dist/phases/code-refine-verification/verifier.js +0 -597
- package/dist/phases/code-review/analyzer.d.ts +0 -29
- package/dist/phases/code-review/analyzer.js +0 -363
- package/dist/phases/code-review/context-fetcher.d.ts +0 -92
- package/dist/phases/code-review/context-fetcher.js +0 -296
- package/dist/phases/feature-analysis/analyzer-helpers.d.ts +0 -10
- package/dist/phases/feature-analysis/analyzer-helpers.js +0 -47
- package/dist/phases/feature-analysis/analyzer.d.ts +0 -11
- package/dist/phases/feature-analysis/analyzer.js +0 -208
- package/dist/phases/feature-analysis/context-fetcher.d.ts +0 -26
- package/dist/phases/feature-analysis/context-fetcher.js +0 -134
- package/dist/phases/feature-analysis/http-fallback.d.ts +0 -20
- package/dist/phases/feature-analysis/http-fallback.js +0 -95
- package/dist/phases/feature-analysis/mcp-server.d.ts +0 -1
- package/dist/phases/feature-analysis/mcp-server.js +0 -144
- package/dist/phases/feature-analysis/prompts-improvement.d.ts +0 -8
- package/dist/phases/feature-analysis/prompts-improvement.js +0 -109
- package/dist/phases/feature-analysis-verification/verifier.d.ts +0 -37
- package/dist/phases/feature-analysis-verification/verifier.js +0 -147
- package/dist/phases/technical-design/analyzer-helpers.d.ts +0 -25
- package/dist/phases/technical-design/analyzer-helpers.js +0 -39
- package/dist/phases/technical-design/analyzer.d.ts +0 -21
- package/dist/phases/technical-design/analyzer.js +0 -461
- package/dist/phases/technical-design/context-fetcher.d.ts +0 -12
- package/dist/phases/technical-design/context-fetcher.js +0 -39
- package/dist/phases/technical-design/http-fallback.d.ts +0 -17
- package/dist/phases/technical-design/http-fallback.js +0 -151
- package/dist/phases/technical-design/mcp-server.d.ts +0 -1
- package/dist/phases/technical-design/mcp-server.js +0 -157
- package/dist/phases/technical-design/prompts-improvement.d.ts +0 -5
- package/dist/phases/technical-design/prompts-improvement.js +0 -93
- package/dist/phases/technical-design-verification/verifier.d.ts +0 -53
- package/dist/phases/technical-design-verification/verifier.js +0 -170
- package/dist/services/feature-branches.d.ts +0 -77
- package/dist/services/feature-branches.js +0 -205
- package/dist/workflow-runner/config/phase-configs.d.ts +0 -5
- package/dist/workflow-runner/config/phase-configs.js +0 -120
- package/dist/workflow-runner/core/feature-filter.d.ts +0 -16
- package/dist/workflow-runner/core/feature-filter.js +0 -46
- package/dist/workflow-runner/core/index.d.ts +0 -8
- package/dist/workflow-runner/core/index.js +0 -12
- package/dist/workflow-runner/core/pipeline-evaluator.d.ts +0 -24
- package/dist/workflow-runner/core/pipeline-evaluator.js +0 -32
- package/dist/workflow-runner/core/state-manager.d.ts +0 -24
- package/dist/workflow-runner/core/state-manager.js +0 -42
- package/dist/workflow-runner/core/workflow-logger.d.ts +0 -20
- package/dist/workflow-runner/core/workflow-logger.js +0 -65
- package/dist/workflow-runner/executors/phase-executor.d.ts +0 -8
- package/dist/workflow-runner/executors/phase-executor.js +0 -248
- package/dist/workflow-runner/feature-workflow-runner.d.ts +0 -26
- package/dist/workflow-runner/feature-workflow-runner.js +0 -119
- package/dist/workflow-runner/index.d.ts +0 -2
- package/dist/workflow-runner/index.js +0 -2
- package/dist/workflow-runner/pipeline-runner.d.ts +0 -17
- package/dist/workflow-runner/pipeline-runner.js +0 -393
- package/dist/workflow-runner/workflow-processor.d.ts +0 -54
- package/dist/workflow-runner/workflow-processor.js +0 -170
|
@@ -5,6 +5,19 @@
|
|
|
5
5
|
import { Octokit } from '@octokit/rest';
|
|
6
6
|
import { execSync } from 'child_process';
|
|
7
7
|
import { logInfo, logError } from '../../utils/logger.js';
|
|
8
|
+
// GitHub PR title best practice: keep under 72 characters
|
|
9
|
+
const MAX_PR_TITLE_LENGTH = 72;
|
|
10
|
+
const PR_TITLE_PREFIX = 'feat: ';
|
|
11
|
+
const MAX_FEATURE_NAME_LENGTH = MAX_PR_TITLE_LENGTH - PR_TITLE_PREFIX.length;
|
|
12
|
+
/**
|
|
13
|
+
* Truncate text to a maximum length, adding ellipsis if truncated
|
|
14
|
+
*/
|
|
15
|
+
function truncateText(text, maxLength) {
|
|
16
|
+
if (text.length <= maxLength) {
|
|
17
|
+
return text;
|
|
18
|
+
}
|
|
19
|
+
return text.slice(0, maxLength - 3) + '...';
|
|
20
|
+
}
|
|
8
21
|
/**
|
|
9
22
|
* Convert a feat/ branch name to a dev/ branch name
|
|
10
23
|
* e.g., "feat/abc123/1-database" -> "dev/abc123/1-database"
|
|
@@ -142,8 +155,9 @@ export async function createBranchPullRequest(config, devBranchName, featureName
|
|
|
142
155
|
pullRequestNumber: existingPR.number,
|
|
143
156
|
};
|
|
144
157
|
}
|
|
145
|
-
// Generate PR title and body
|
|
146
|
-
const
|
|
158
|
+
// Generate PR title and body (truncate to keep under 72 chars)
|
|
159
|
+
const truncatedName = truncateText(featureName, MAX_FEATURE_NAME_LENGTH);
|
|
160
|
+
const title = `${PR_TITLE_PREFIX}${truncatedName}`;
|
|
147
161
|
const body = `## Branch Implementation
|
|
148
162
|
|
|
149
163
|
${branchDescription}
|
|
@@ -10,6 +10,16 @@ import { prepareCustomBranchGitEnvironment, syncFeatBranchWithMain, } from '../.
|
|
|
10
10
|
import { getCurrentBranch, updateBranch, getBranches, createBranches, getBaseBranchInfo, } from '../../services/branches.js';
|
|
11
11
|
import { createBranchPullRequest, } from './branch-pr-creator.js';
|
|
12
12
|
import { getGitHubConfig } from '../../api/github.js';
|
|
13
|
+
import { getFeature } from '../../api/features/index.js';
|
|
14
|
+
/**
|
|
15
|
+
* Truncate text to a maximum length, adding ellipsis if truncated
|
|
16
|
+
*/
|
|
17
|
+
function truncateText(text, maxLength) {
|
|
18
|
+
if (text.length <= maxLength) {
|
|
19
|
+
return text;
|
|
20
|
+
}
|
|
21
|
+
return text.slice(0, maxLength - 3) + '...';
|
|
22
|
+
}
|
|
13
23
|
function userMessage(content) {
|
|
14
24
|
return {
|
|
15
25
|
type: 'user',
|
|
@@ -50,11 +60,25 @@ export const implementFeatureCode = async (options, config, checklistContext) =>
|
|
|
50
60
|
if (verbose) {
|
|
51
61
|
logInfo(`š Creating default branch record for feature: ${featureId}`);
|
|
52
62
|
}
|
|
63
|
+
// Fetch feature info to get the feature name for branch naming
|
|
64
|
+
let featureName = 'Feature Implementation';
|
|
65
|
+
try {
|
|
66
|
+
const featureInfo = await getFeature(featureId, verbose);
|
|
67
|
+
if (featureInfo?.name) {
|
|
68
|
+
// Truncate feature name for branch display (max 100 chars)
|
|
69
|
+
featureName = truncateText(featureInfo.name, 100);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (verbose) {
|
|
74
|
+
logInfo(`Could not fetch feature name, using default: ${error}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
53
77
|
const defaultBranchName = `dev/${featureId}`;
|
|
54
78
|
const createdBranches = await createBranches({ featureId, verbose }, [
|
|
55
79
|
{
|
|
56
|
-
name:
|
|
57
|
-
description:
|
|
80
|
+
name: featureName,
|
|
81
|
+
description: `Implementation branch for: ${featureName}`,
|
|
58
82
|
branch_name: defaultBranchName,
|
|
59
83
|
status: 'pending',
|
|
60
84
|
},
|
|
@@ -12,7 +12,7 @@ export interface ThreadAnalysisResult {
|
|
|
12
12
|
* Analyze whether a review thread has been addressed by examining code changes
|
|
13
13
|
* Uses LLM to intelligently determine if the feedback was addressed
|
|
14
14
|
*/
|
|
15
|
-
export declare function analyzeThreadWithLLM(thread: ReviewThread, fileChange: PRFileChange | undefined, config: EdsgerConfig, verbose?: boolean): Promise<ThreadAnalysisResult>;
|
|
15
|
+
export declare function analyzeThreadWithLLM(thread: ReviewThread, fileChange: PRFileChange | undefined, allFileChanges: PRFileChange[], config: EdsgerConfig, verbose?: boolean): Promise<ThreadAnalysisResult>;
|
|
16
16
|
/**
|
|
17
17
|
* Analyze all review threads in parallel using LLM
|
|
18
18
|
*/
|
|
@@ -9,7 +9,7 @@ import { createThreadAnalysisPrompt } from './prompts.js';
|
|
|
9
9
|
* Analyze whether a review thread has been addressed by examining code changes
|
|
10
10
|
* Uses LLM to intelligently determine if the feedback was addressed
|
|
11
11
|
*/
|
|
12
|
-
export async function analyzeThreadWithLLM(thread, fileChange, config, verbose) {
|
|
12
|
+
export async function analyzeThreadWithLLM(thread, fileChange, allFileChanges, config, verbose) {
|
|
13
13
|
const firstComment = thread.comments.nodes[0];
|
|
14
14
|
if (!firstComment) {
|
|
15
15
|
return {
|
|
@@ -17,25 +17,26 @@ export async function analyzeThreadWithLLM(thread, fileChange, config, verbose)
|
|
|
17
17
|
reason: 'Comment thread exists but has no comments',
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
-
// If file was not changed at all, feedback definitely not addressed
|
|
21
|
-
if (!fileChange || !fileChange.patch) {
|
|
22
|
-
return {
|
|
23
|
-
isAddressed: false,
|
|
24
|
-
reason: `File ${firstComment.path} has not been modified in this PR`,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
20
|
// If file was deleted, thread should be resolved as obsolete
|
|
28
|
-
if (fileChange
|
|
21
|
+
if (fileChange?.status === 'removed') {
|
|
29
22
|
return {
|
|
30
23
|
isAddressed: true,
|
|
31
24
|
reason: 'File has been removed',
|
|
32
25
|
};
|
|
33
26
|
}
|
|
27
|
+
// Check if there are any file changes at all
|
|
28
|
+
const hasAnyChanges = allFileChanges.some((fc) => fc.patch);
|
|
29
|
+
if (!hasAnyChanges) {
|
|
30
|
+
return {
|
|
31
|
+
isAddressed: false,
|
|
32
|
+
reason: 'No code changes found in this PR',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
34
35
|
try {
|
|
35
36
|
if (verbose) {
|
|
36
37
|
logInfo(`š¤ Using LLM to analyze if comment in ${firstComment.path}:${firstComment.line} has been addressed...`);
|
|
37
38
|
}
|
|
38
|
-
const analysisPrompt = createThreadAnalysisPrompt(thread, fileChange, firstComment);
|
|
39
|
+
const analysisPrompt = createThreadAnalysisPrompt(thread, fileChange, allFileChanges, firstComment);
|
|
39
40
|
let lastResponse = '';
|
|
40
41
|
let analysisResult = null;
|
|
41
42
|
function* userMessage() {
|
|
@@ -119,7 +120,7 @@ export async function analyzeAllThreads(threads, fileChanges, config, verbose) {
|
|
|
119
120
|
const results = await Promise.all(threads.map(async (thread) => {
|
|
120
121
|
const firstComment = thread.comments.nodes[0];
|
|
121
122
|
const fileChange = fileChanges.find((fc) => fc.filename === firstComment?.path);
|
|
122
|
-
const analysis = await analyzeThreadWithLLM(thread, fileChange, config, verbose);
|
|
123
|
+
const analysis = await analyzeThreadWithLLM(thread, fileChange, fileChanges, config, verbose);
|
|
123
124
|
return {
|
|
124
125
|
thread,
|
|
125
126
|
analysis,
|
|
@@ -2,4 +2,4 @@ import { ReviewThread, PRFileChange } from './types.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Create prompt for LLM to analyze if a comment thread has been addressed
|
|
4
4
|
*/
|
|
5
|
-
export declare function createThreadAnalysisPrompt(thread: ReviewThread, fileChange: PRFileChange, firstComment: ReviewThread['comments']['nodes'][0]): string;
|
|
5
|
+
export declare function createThreadAnalysisPrompt(thread: ReviewThread, fileChange: PRFileChange | undefined, allFileChanges: PRFileChange[], firstComment: ReviewThread['comments']['nodes'][0]): string;
|
|
@@ -1,44 +1,86 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Create prompt for LLM to analyze if a comment thread has been addressed
|
|
3
3
|
*/
|
|
4
|
-
export function createThreadAnalysisPrompt(thread, fileChange, firstComment) {
|
|
4
|
+
export function createThreadAnalysisPrompt(thread, fileChange, allFileChanges, firstComment) {
|
|
5
5
|
const allComments = thread.comments.nodes
|
|
6
6
|
.map((c, idx) => `Comment ${idx + 1} by @${c.author.login}:\n${c.body}`)
|
|
7
7
|
.join('\n\n');
|
|
8
8
|
// Build the code context section
|
|
9
9
|
let codeContext = '';
|
|
10
|
-
|
|
11
|
-
if
|
|
12
|
-
|
|
10
|
+
const commentFilePath = firstComment.path;
|
|
11
|
+
// Check if the comment's file was modified
|
|
12
|
+
const commentFileModified = fileChange && fileChange.patch;
|
|
13
|
+
if (commentFileModified) {
|
|
14
|
+
// Include diff for the comment's file
|
|
15
|
+
codeContext += `**Changes in ${commentFilePath} (where the comment was made):**
|
|
13
16
|
\`\`\`diff
|
|
14
17
|
${fileChange.patch}
|
|
15
18
|
\`\`\`
|
|
16
19
|
|
|
17
20
|
`;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
: fileChange.fullContent;
|
|
27
|
-
codeContext += `**Complete File Content (After Changes):**
|
|
21
|
+
// Include full file content for better context
|
|
22
|
+
if (fileChange.fullContent) {
|
|
23
|
+
const maxLength = 10000;
|
|
24
|
+
const content = fileChange.fullContent.length > maxLength
|
|
25
|
+
? fileChange.fullContent.substring(0, maxLength) +
|
|
26
|
+
'\n\n... (file truncated, showing first 10000 characters)'
|
|
27
|
+
: fileChange.fullContent;
|
|
28
|
+
codeContext += `**Complete File Content of ${commentFilePath} (After Changes):**
|
|
28
29
|
\`\`\`
|
|
29
30
|
${content}
|
|
30
31
|
\`\`\`
|
|
31
32
|
|
|
32
33
|
`;
|
|
34
|
+
}
|
|
33
35
|
}
|
|
34
|
-
|
|
35
|
-
codeContext
|
|
36
|
+
else {
|
|
37
|
+
codeContext += `**Note:** The file where the comment was made (${commentFilePath}) was NOT modified in this PR.
|
|
38
|
+
This could be intentional - the comment may be requesting changes to a DIFFERENT file.
|
|
39
|
+
|
|
40
|
+
`;
|
|
41
|
+
}
|
|
42
|
+
// Include other file changes - important for cross-file requests
|
|
43
|
+
// (e.g., "add these variables to the env example file")
|
|
44
|
+
const otherChanges = allFileChanges.filter((fc) => fc.filename !== commentFilePath && fc.patch);
|
|
45
|
+
if (otherChanges.length > 0) {
|
|
46
|
+
codeContext += `**Other Files Changed in This PR:**\n`;
|
|
47
|
+
// Show summary of all changed files first
|
|
48
|
+
codeContext += `Changed files: ${otherChanges.map((fc) => fc.filename).join(', ')}\n\n`;
|
|
49
|
+
// Include diffs for potentially relevant files (env files, config files, etc.)
|
|
50
|
+
// and a sample of other changes
|
|
51
|
+
const relevantPatterns = [
|
|
52
|
+
/\.env/i,
|
|
53
|
+
/config/i,
|
|
54
|
+
/example/i,
|
|
55
|
+
/sample/i,
|
|
56
|
+
/template/i,
|
|
57
|
+
];
|
|
58
|
+
const relevantChanges = otherChanges.filter((fc) => relevantPatterns.some((pattern) => pattern.test(fc.filename)));
|
|
59
|
+
const otherSampleChanges = otherChanges
|
|
60
|
+
.filter((fc) => !relevantChanges.includes(fc))
|
|
61
|
+
.slice(0, 3); // Limit to avoid context overflow
|
|
62
|
+
const changesToShow = [...relevantChanges, ...otherSampleChanges];
|
|
63
|
+
for (const change of changesToShow) {
|
|
64
|
+
if (change.patch) {
|
|
65
|
+
codeContext += `**Changes in ${change.filename}:**
|
|
66
|
+
\`\`\`diff
|
|
67
|
+
${change.patch}
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (otherChanges.length > changesToShow.length) {
|
|
74
|
+
codeContext += `(${otherChanges.length - changesToShow.length} additional files changed but not shown)\n\n`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!codeContext.includes('```')) {
|
|
78
|
+
codeContext = '(No code changes available)\n\n';
|
|
36
79
|
}
|
|
37
80
|
return `You are analyzing whether a code review comment has been addressed by subsequent code changes.
|
|
38
81
|
|
|
39
82
|
**Review Thread Information:**
|
|
40
|
-
-
|
|
41
|
-
- Line: ${firstComment.line || 'N/A'}
|
|
83
|
+
- Comment Location: ${firstComment.path}:${firstComment.line || 'N/A'}
|
|
42
84
|
- Thread has ${thread.comments.totalCount} comment(s)
|
|
43
85
|
|
|
44
86
|
**Review Comments:**
|
|
@@ -47,21 +89,20 @@ ${allComments}
|
|
|
47
89
|
${codeContext}
|
|
48
90
|
|
|
49
91
|
**Your Task:**
|
|
50
|
-
Analyze whether the code changes adequately address the feedback in the review comments.
|
|
51
|
-
1. **The diff** showing what was changed
|
|
52
|
-
2. **The complete file content** after changes for full context
|
|
92
|
+
Analyze whether the code changes adequately address the feedback in the review comments.
|
|
53
93
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
5. Use the complete file to verify the fix is properly integrated
|
|
94
|
+
**IMPORTANT - Cross-File Requests:**
|
|
95
|
+
- A comment on file A may request changes to file B (e.g., "add this to the env example file")
|
|
96
|
+
- The comment may use variable names (like "clientId") that differ from the actual environment variable names (like "SPOKE_CLIENT_ID")
|
|
97
|
+
- Focus on whether the **intent** of the feedback was addressed, regardless of which file was modified
|
|
98
|
+
- Check ALL changed files, not just the file where the comment was made
|
|
60
99
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
100
|
+
Consider:
|
|
101
|
+
1. Does the feedback request a specific code change? What is the **intent**?
|
|
102
|
+
2. Have those changes (or equivalent changes) been made in ANY file?
|
|
103
|
+
3. If the comment mentions adding something to a config/env file, check if those files were modified
|
|
104
|
+
4. Variable names in comments may not match actual implementation names
|
|
105
|
+
5. Focus on whether the underlying issue was addressed, not literal string matching
|
|
65
106
|
|
|
66
107
|
Return your analysis in this JSON format:
|
|
67
108
|
\`\`\`json
|
|
@@ -72,9 +113,8 @@ Return your analysis in this JSON format:
|
|
|
72
113
|
\`\`\`
|
|
73
114
|
|
|
74
115
|
Example responses:
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
- If the full context shows the issue is resolved differently: {"isAddressed": true, "reason": "Issue resolved through alternative implementation visible in full file"}
|
|
116
|
+
- {"isAddressed": true, "reason": "Null check added in the updated code"}
|
|
117
|
+
- {"isAddressed": false, "reason": "No relevant changes found to address the feedback"}
|
|
118
|
+
- {"isAddressed": true, "reason": "Requested changes made in the appropriate file"}
|
|
79
119
|
`;
|
|
80
120
|
}
|
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Octokit } from '@octokit/rest';
|
|
6
6
|
import { execSync } from 'child_process';
|
|
7
|
+
// GitHub PR title best practice: keep under 72 characters
|
|
8
|
+
const MAX_PR_TITLE_LENGTH = 72;
|
|
9
|
+
const PR_TITLE_PREFIX = 'feat: ';
|
|
10
|
+
const MAX_FEATURE_NAME_LENGTH = MAX_PR_TITLE_LENGTH - PR_TITLE_PREFIX.length;
|
|
11
|
+
/**
|
|
12
|
+
* Truncate text to a maximum length, adding ellipsis if truncated
|
|
13
|
+
*/
|
|
14
|
+
function truncateText(text, maxLength) {
|
|
15
|
+
if (text.length <= maxLength) {
|
|
16
|
+
return text;
|
|
17
|
+
}
|
|
18
|
+
return text.slice(0, maxLength - 3) + '...';
|
|
19
|
+
}
|
|
7
20
|
/**
|
|
8
21
|
* Get current Git branch name
|
|
9
22
|
*/
|
|
@@ -108,12 +121,14 @@ const switchToMainBranch = (mainBranch = 'main', verbose) => {
|
|
|
108
121
|
};
|
|
109
122
|
/**
|
|
110
123
|
* Generate pull request title from feature name
|
|
124
|
+
* Truncates to keep under 72 characters (GitHub best practice)
|
|
111
125
|
*/
|
|
112
126
|
const generatePRTitle = (featureName) => {
|
|
113
127
|
// Remove feature ID prefix if present (e.g., "FEAT-123: Feature Name" -> "Feature Name")
|
|
114
128
|
const cleanName = featureName.replace(/^[A-Z]+-\d+:\s*/, '');
|
|
115
|
-
//
|
|
116
|
-
|
|
129
|
+
// Truncate to keep total title under 72 chars
|
|
130
|
+
const truncatedName = truncateText(cleanName.toLowerCase(), MAX_FEATURE_NAME_LENGTH);
|
|
131
|
+
return `${PR_TITLE_PREFIX}${truncatedName}`;
|
|
117
132
|
};
|
|
118
133
|
/**
|
|
119
134
|
* Check if a pull request already exists from head to base
|
package/package.json
CHANGED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Read(//Users/steven/development/edsger/**)",
|
|
5
|
-
"Bash(npm run build)",
|
|
6
|
-
"Bash(node:*)",
|
|
7
|
-
"Bash(git add:*)",
|
|
8
|
-
"Bash(git commit:*)",
|
|
9
|
-
"Bash(ls:*)",
|
|
10
|
-
"Bash(cat:*)",
|
|
11
|
-
"Bash(npm run typecheck:*)",
|
|
12
|
-
"Bash(git diff:*)",
|
|
13
|
-
"WebSearch",
|
|
14
|
-
"WebFetch(domain:supabase.com)",
|
|
15
|
-
"Bash(npm install:*)",
|
|
16
|
-
"Bash(grep:*)",
|
|
17
|
-
"Bash(npx supabase gen types typescript --help:*)",
|
|
18
|
-
"Bash(git -C /Users/steven/development/edsger status)",
|
|
19
|
-
"Bash(git -C /Users/steven/development/edsger diff)",
|
|
20
|
-
"Bash(git -C /Users/steven/development/edsger log --oneline -5)",
|
|
21
|
-
"Bash(git -C /Users/steven/development/edsger add supabase/migrations/20251231000000_drop_unused_views.sql)",
|
|
22
|
-
"Bash(git -C /Users/steven/development/edsger commit -m \"$\\(cat <<''EOF''\nchore: drop unused database views\n\nRemove test_report_summary and user_stories_with_context views that are defined but never used in the application.\n\nš¤ Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
|
|
23
|
-
"Bash(git -C /Users/steven/development/edsger commit -m \"$\\(cat <<''EOF''\nchore: drop unused database views\n\nRemove test_report_summary and user_stories_with_context views\nthat are defined but never used in the application.\n\nš¤ Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")"
|
|
24
|
-
],
|
|
25
|
-
"deny": [],
|
|
26
|
-
"ask": []
|
|
27
|
-
}
|
|
28
|
-
}
|
package/.env.local
DELETED