@ariso-ai/ivan 1.0.10 → 1.0.12
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/services/address-task-executor.d.ts +1 -1
- package/dist/services/address-task-executor.d.ts.map +1 -1
- package/dist/services/address-task-executor.js +163 -84
- package/dist/services/address-task-executor.js.map +1 -1
- package/dist/services/claude-cli-executor.d.ts +1 -0
- package/dist/services/claude-cli-executor.d.ts.map +1 -1
- package/dist/services/claude-cli-executor.js +5 -0
- package/dist/services/claude-cli-executor.js.map +1 -1
- package/dist/services/claude-executor.d.ts +1 -0
- package/dist/services/claude-executor.d.ts.map +1 -1
- package/dist/services/claude-executor.js +27 -14
- package/dist/services/claude-executor.js.map +1 -1
- package/dist/services/executor-factory.d.ts +1 -0
- package/dist/services/executor-factory.d.ts.map +1 -1
- package/dist/services/executor-factory.js.map +1 -1
- package/dist/services/git-interfaces.d.ts +1 -0
- package/dist/services/git-interfaces.d.ts.map +1 -1
- package/dist/services/git-manager-cli.d.ts +1 -0
- package/dist/services/git-manager-cli.d.ts.map +1 -1
- package/dist/services/git-manager-cli.js +1 -0
- package/dist/services/git-manager-cli.js.map +1 -1
- package/dist/services/git-manager-pat.d.ts +1 -0
- package/dist/services/git-manager-pat.d.ts.map +1 -1
- package/dist/services/git-manager-pat.js +64 -32
- package/dist/services/git-manager-pat.js.map +1 -1
- package/dist/services/github-api-client.d.ts.map +1 -1
- package/dist/services/github-api-client.js +22 -5
- package/dist/services/github-api-client.js.map +1 -1
- package/dist/services/task-executor.d.ts.map +1 -1
- package/dist/services/task-executor.js +177 -145
- package/dist/services/task-executor.js.map +1 -1
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@ export declare class AddressTaskExecutor {
|
|
|
11
11
|
constructor();
|
|
12
12
|
private getClaudeExecutor;
|
|
13
13
|
private getOpenAIService;
|
|
14
|
-
executeAddressTasks(tasks: Task[]): Promise<void>;
|
|
14
|
+
executeAddressTasks(tasks: Task[], quiet?: boolean): Promise<void>;
|
|
15
15
|
private getUnaddressedComments;
|
|
16
16
|
private generateReviewInstructions;
|
|
17
17
|
private tryCommitWithFixes;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address-task-executor.d.ts","sourceRoot":"","sources":["../../src/services/address-task-executor.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAItC,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,gBAAgB,CAAqB;;IAQ7C,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,gBAAgB;IAOlB,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"address-task-executor.d.ts","sourceRoot":"","sources":["../../src/services/address-task-executor.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAItC,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,gBAAgB,CAAqB;;IAQ7C,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,gBAAgB;IAOlB,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;YA8pBjE,sBAAsB;YAwGtB,0BAA0B;YAyD1B,kBAAkB;CAuEjC"}
|
|
@@ -32,13 +32,16 @@ export class AddressTaskExecutor {
|
|
|
32
32
|
}
|
|
33
33
|
return this.openaiService;
|
|
34
34
|
}
|
|
35
|
-
async executeAddressTasks(tasks) {
|
|
35
|
+
async executeAddressTasks(tasks, quiet = false) {
|
|
36
36
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
if (!quiet) {
|
|
38
|
+
console.log(chalk.blue.bold('🚀 Starting address task workflow'));
|
|
39
|
+
console.log('');
|
|
40
|
+
}
|
|
39
41
|
// Validate dependencies
|
|
40
42
|
await this.getClaudeExecutor().validateClaudeCodeInstallation();
|
|
41
|
-
|
|
43
|
+
if (!quiet)
|
|
44
|
+
console.log(chalk.green('✅ Claude Code SDK configured'));
|
|
42
45
|
// Get working directory from first task's job
|
|
43
46
|
const db = this.jobManager['dbManager'].getKysely();
|
|
44
47
|
const job = await db
|
|
@@ -53,9 +56,11 @@ export class AddressTaskExecutor {
|
|
|
53
56
|
this.gitManager = createGitManager(this.workingDir);
|
|
54
57
|
this.prService = createPRService(this.workingDir);
|
|
55
58
|
this.gitManager.validateGitHubCliInstallation();
|
|
56
|
-
|
|
59
|
+
if (!quiet)
|
|
60
|
+
console.log(chalk.green('✅ GitHub CLI is installed'));
|
|
57
61
|
this.gitManager.validateGitHubCliAuthentication();
|
|
58
|
-
|
|
62
|
+
if (!quiet)
|
|
63
|
+
console.log(chalk.green('✅ GitHub CLI is authenticated'));
|
|
59
64
|
// Load repository instructions
|
|
60
65
|
this.repoInstructions = await this.configManager.getRepoInstructions(this.workingDir);
|
|
61
66
|
// Group tasks by branch
|
|
@@ -73,12 +78,15 @@ export class AddressTaskExecutor {
|
|
|
73
78
|
// Execute tasks grouped by branch
|
|
74
79
|
for (const [branch, branchTasks] of tasksByBranch) {
|
|
75
80
|
if (branch === 'unknown') {
|
|
76
|
-
|
|
81
|
+
if (!quiet)
|
|
82
|
+
console.log(chalk.yellow('⚠️ Skipping tasks without branch information'));
|
|
77
83
|
continue;
|
|
78
84
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
if (!quiet) {
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log(chalk.cyan.bold(`🔄 Creating worktree for branch: ${branch}`));
|
|
88
|
+
}
|
|
89
|
+
let spinner = quiet ? null : ora('Creating worktree...').start();
|
|
82
90
|
let worktreePath = null;
|
|
83
91
|
try {
|
|
84
92
|
// Create worktree for the branch
|
|
@@ -87,11 +95,14 @@ export class AddressTaskExecutor {
|
|
|
87
95
|
}
|
|
88
96
|
worktreePath = await this.gitManager.createWorktree(branch);
|
|
89
97
|
this.gitManager.switchToWorktree(worktreePath);
|
|
90
|
-
spinner
|
|
98
|
+
if (spinner)
|
|
99
|
+
spinner.succeed(`Worktree created: ${worktreePath}`);
|
|
91
100
|
}
|
|
92
101
|
catch (error) {
|
|
93
|
-
spinner
|
|
94
|
-
|
|
102
|
+
if (spinner)
|
|
103
|
+
spinner.fail(`Failed to create worktree for branch: ${branch}`);
|
|
104
|
+
if (!quiet)
|
|
105
|
+
console.error(error);
|
|
95
106
|
continue;
|
|
96
107
|
}
|
|
97
108
|
// Handle lint_and_test tasks separately
|
|
@@ -99,30 +110,38 @@ export class AddressTaskExecutor {
|
|
|
99
110
|
const addressTasks = branchTasks.filter(t => t.type === 'address');
|
|
100
111
|
// Process lint_and_test tasks first
|
|
101
112
|
for (const task of lintAndTestTasks) {
|
|
102
|
-
|
|
103
|
-
|
|
113
|
+
if (!quiet) {
|
|
114
|
+
console.log('');
|
|
115
|
+
console.log(chalk.blue('🔧 Fixing test and lint failures'));
|
|
116
|
+
}
|
|
104
117
|
await this.jobManager.updateTaskStatus(task.uuid, 'active');
|
|
105
118
|
// Extract PR number from task description
|
|
106
119
|
const prNumberMatch = task.description.match(/PR #(\d+)/);
|
|
107
120
|
const taskPrNumber = prNumberMatch ? parseInt(prNumberMatch[1]) : null;
|
|
108
|
-
|
|
121
|
+
if (!quiet)
|
|
122
|
+
spinner = ora('Fetching GitHub Actions logs...').start();
|
|
109
123
|
let actionLogs = '';
|
|
110
124
|
if (taskPrNumber && this.prService) {
|
|
111
125
|
try {
|
|
112
126
|
actionLogs = await this.prService.getFailingActionLogs(taskPrNumber);
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
127
|
+
if (spinner) {
|
|
128
|
+
if (actionLogs) {
|
|
129
|
+
spinner.succeed('GitHub Actions logs fetched');
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
spinner.info('No failing action logs found');
|
|
133
|
+
}
|
|
118
134
|
}
|
|
119
135
|
}
|
|
120
136
|
catch (error) {
|
|
121
|
-
spinner
|
|
122
|
-
|
|
137
|
+
if (spinner)
|
|
138
|
+
spinner.warn('Could not fetch GitHub Actions logs');
|
|
139
|
+
if (!quiet)
|
|
140
|
+
console.error(error);
|
|
123
141
|
}
|
|
124
142
|
}
|
|
125
|
-
|
|
143
|
+
if (!quiet)
|
|
144
|
+
spinner = ora('Running Claude Code to fix test and lint failures...').start();
|
|
126
145
|
// Prepare the prompt for Claude
|
|
127
146
|
let prompt = 'Fix the failing tests and linting issues in this PR.\n\n';
|
|
128
147
|
prompt += 'The following GitHub Actions checks are failing:\n';
|
|
@@ -140,30 +159,35 @@ export class AddressTaskExecutor {
|
|
|
140
159
|
}
|
|
141
160
|
try {
|
|
142
161
|
const result = await this.getClaudeExecutor().executeTask(prompt, worktreePath || this.workingDir);
|
|
143
|
-
spinner
|
|
162
|
+
if (spinner)
|
|
163
|
+
spinner.succeed('Claude Code execution completed');
|
|
144
164
|
await this.jobManager.updateTaskExecutionLog(task.uuid, result.log);
|
|
145
165
|
if (!this.gitManager) {
|
|
146
166
|
throw new Error('GitManager not initialized');
|
|
147
167
|
}
|
|
148
168
|
const changedFiles = this.gitManager.getChangedFiles();
|
|
149
169
|
if (changedFiles.length === 0) {
|
|
150
|
-
|
|
170
|
+
if (!quiet)
|
|
171
|
+
console.log(chalk.yellow('⚠️ No changes made'));
|
|
151
172
|
await this.jobManager.updateTaskStatus(task.uuid, 'completed');
|
|
152
173
|
continue;
|
|
153
174
|
}
|
|
154
175
|
// Create commit with co-author
|
|
155
|
-
|
|
176
|
+
if (!quiet)
|
|
177
|
+
spinner = ora('Creating commit...').start();
|
|
156
178
|
const commitMessage = 'Fix test and lint failures\n\nCo-authored-by: ivan-agent <ivan-agent@users.noreply.github.com>';
|
|
157
179
|
if (!this.gitManager) {
|
|
158
180
|
throw new Error('GitManager not initialized');
|
|
159
181
|
}
|
|
160
182
|
// Try to commit, handling pre-commit hook failures
|
|
161
|
-
const commitResult = await this.tryCommitWithFixes(commitMessage, task, worktreePath || this.workingDir, spinner);
|
|
183
|
+
const commitResult = await this.tryCommitWithFixes(commitMessage, task, worktreePath || this.workingDir, spinner, quiet);
|
|
162
184
|
if (commitResult.succeeded) {
|
|
163
|
-
spinner
|
|
185
|
+
if (spinner)
|
|
186
|
+
spinner.succeed('Changes committed');
|
|
164
187
|
}
|
|
165
188
|
else {
|
|
166
|
-
spinner
|
|
189
|
+
if (spinner)
|
|
190
|
+
spinner.fail('Failed to commit after multiple attempts');
|
|
167
191
|
throw new Error('Pre-commit hook failures could not be fixed');
|
|
168
192
|
}
|
|
169
193
|
// Get the commit hash
|
|
@@ -174,21 +198,26 @@ export class AddressTaskExecutor {
|
|
|
174
198
|
// Save commit hash to task
|
|
175
199
|
await this.jobManager.updateTaskCommit(task.uuid, commitHash);
|
|
176
200
|
// Push the commit immediately
|
|
177
|
-
|
|
201
|
+
if (!quiet)
|
|
202
|
+
spinner = ora('Pushing commit...').start();
|
|
178
203
|
try {
|
|
179
204
|
if (!this.gitManager) {
|
|
180
205
|
throw new Error('GitManager not initialized');
|
|
181
206
|
}
|
|
182
207
|
await this.gitManager.pushBranch(branch);
|
|
183
|
-
spinner
|
|
208
|
+
if (spinner)
|
|
209
|
+
spinner.succeed('Commit pushed successfully');
|
|
184
210
|
}
|
|
185
211
|
catch (error) {
|
|
186
|
-
spinner
|
|
187
|
-
|
|
212
|
+
if (spinner)
|
|
213
|
+
spinner.fail('Failed to push commit');
|
|
214
|
+
if (!quiet)
|
|
215
|
+
console.error(error);
|
|
188
216
|
}
|
|
189
217
|
// Add review comment for lint_and_test task
|
|
190
218
|
if (taskPrNumber) {
|
|
191
|
-
|
|
219
|
+
if (!quiet)
|
|
220
|
+
spinner = ora('Adding review request comment...').start();
|
|
192
221
|
try {
|
|
193
222
|
const reviewAgent = this.configManager.getReviewAgent();
|
|
194
223
|
const reviewComment = `${reviewAgent} please review the test and lint fixes that were applied to address the failing CI checks`;
|
|
@@ -196,18 +225,23 @@ export class AddressTaskExecutor {
|
|
|
196
225
|
cwd: worktreePath || this.workingDir,
|
|
197
226
|
stdio: 'pipe'
|
|
198
227
|
});
|
|
199
|
-
spinner
|
|
228
|
+
if (spinner)
|
|
229
|
+
spinner.succeed('Review request comment added');
|
|
200
230
|
}
|
|
201
231
|
catch (error) {
|
|
202
|
-
spinner
|
|
203
|
-
|
|
232
|
+
if (spinner)
|
|
233
|
+
spinner.fail('Failed to add review comment');
|
|
234
|
+
if (!quiet)
|
|
235
|
+
console.error(error);
|
|
204
236
|
}
|
|
205
237
|
}
|
|
206
238
|
await this.jobManager.updateTaskStatus(task.uuid, 'completed');
|
|
207
239
|
}
|
|
208
240
|
catch (error) {
|
|
209
|
-
spinner
|
|
210
|
-
|
|
241
|
+
if (spinner)
|
|
242
|
+
spinner.fail('Failed to fix test and lint failures');
|
|
243
|
+
if (!quiet)
|
|
244
|
+
console.error(error);
|
|
211
245
|
const errorLog = error instanceof Error ? error.message : String(error);
|
|
212
246
|
await this.jobManager.updateTaskExecutionLog(task.uuid, `ERROR: ${errorLog}`);
|
|
213
247
|
await this.jobManager.updateTaskStatus(task.uuid, 'not_started');
|
|
@@ -225,18 +259,22 @@ export class AddressTaskExecutor {
|
|
|
225
259
|
continue;
|
|
226
260
|
}
|
|
227
261
|
// Get all unaddressed comments for this PR
|
|
228
|
-
|
|
262
|
+
if (!quiet)
|
|
263
|
+
spinner = ora('Fetching PR comments...').start();
|
|
229
264
|
if (!prNumber) {
|
|
230
265
|
throw new Error('PR number not found');
|
|
231
266
|
}
|
|
232
267
|
const comments = await this.getUnaddressedComments(parseInt(prNumber));
|
|
233
|
-
spinner
|
|
268
|
+
if (spinner)
|
|
269
|
+
spinner.succeed(`Found ${comments.length} unaddressed comments`);
|
|
234
270
|
if (comments.length === 0 && addressTasks.some(t => t.description.includes('comment'))) {
|
|
235
|
-
|
|
271
|
+
if (!quiet)
|
|
272
|
+
console.log(chalk.yellow('⚠️ No unaddressed comments found'));
|
|
236
273
|
continue;
|
|
237
274
|
}
|
|
238
275
|
// Process each comment
|
|
239
276
|
for (const comment of comments) {
|
|
277
|
+
// In quiet mode, output the comment being addressed
|
|
240
278
|
console.log('');
|
|
241
279
|
console.log(chalk.blue(`📝 Addressing comment from @${comment.author}:`));
|
|
242
280
|
console.log(chalk.gray(` "${comment.body.substring(0, 100)}${comment.body.length > 100 ? '...' : ''}"`));
|
|
@@ -244,7 +282,8 @@ export class AddressTaskExecutor {
|
|
|
244
282
|
const task = addressTasks.find(t => t.description.includes(comment.author) &&
|
|
245
283
|
t.description.includes(comment.body.substring(0, 50)));
|
|
246
284
|
if (!task) {
|
|
247
|
-
|
|
285
|
+
if (!quiet)
|
|
286
|
+
console.log(chalk.yellow('⚠️ No task found for this comment'));
|
|
248
287
|
continue;
|
|
249
288
|
}
|
|
250
289
|
await this.jobManager.updateTaskStatus(task.uuid, 'active');
|
|
@@ -261,7 +300,8 @@ export class AddressTaskExecutor {
|
|
|
261
300
|
const commentUrl = `https://github.com/${owner.login}/${repoName}/pull/${prNumber}#discussion_r${comment.id}`;
|
|
262
301
|
await this.jobManager.updateTaskCommentUrl(task.uuid, commentUrl);
|
|
263
302
|
}
|
|
264
|
-
|
|
303
|
+
if (!quiet)
|
|
304
|
+
spinner = ora('Running Claude Code to address comment...').start();
|
|
265
305
|
// Prepare the prompt for Claude
|
|
266
306
|
let prompt = 'Address the following PR review comment:\n\n';
|
|
267
307
|
prompt += `Comment from @${comment.author}:\n"${comment.body}"\n\n`;
|
|
@@ -278,7 +318,11 @@ export class AddressTaskExecutor {
|
|
|
278
318
|
}
|
|
279
319
|
try {
|
|
280
320
|
const result = await this.getClaudeExecutor().executeTask(prompt, worktreePath || this.workingDir);
|
|
281
|
-
spinner
|
|
321
|
+
if (spinner) {
|
|
322
|
+
spinner.succeed('Claude Code execution completed');
|
|
323
|
+
}
|
|
324
|
+
// Always output the final message from Claude (even in quiet mode)
|
|
325
|
+
console.log(result.lastMessage);
|
|
282
326
|
await this.jobManager.updateTaskExecutionLog(task.uuid, result.log);
|
|
283
327
|
// Use the last message from Claude's response
|
|
284
328
|
const lastMessage = result.lastMessage;
|
|
@@ -287,9 +331,11 @@ export class AddressTaskExecutor {
|
|
|
287
331
|
}
|
|
288
332
|
const changedFiles = this.gitManager.getChangedFiles();
|
|
289
333
|
if (changedFiles.length === 0) {
|
|
290
|
-
|
|
334
|
+
if (!quiet)
|
|
335
|
+
console.log(chalk.yellow('⚠️ No changes made - Claude determined no changes were needed'));
|
|
291
336
|
// Reply to the comment explaining why no changes were made
|
|
292
|
-
|
|
337
|
+
if (!quiet)
|
|
338
|
+
spinner = ora('Replying to comment...').start();
|
|
293
339
|
try {
|
|
294
340
|
// Truncate the message if it's too long (GitHub has a 65536 character limit)
|
|
295
341
|
const maxLength = 60000;
|
|
@@ -364,21 +410,25 @@ export class AddressTaskExecutor {
|
|
|
364
410
|
cwd: worktreePath || this.workingDir,
|
|
365
411
|
stdio: 'pipe'
|
|
366
412
|
});
|
|
367
|
-
spinner
|
|
413
|
+
if (spinner)
|
|
414
|
+
spinner.succeed('Reply added to comment');
|
|
368
415
|
}
|
|
369
416
|
finally {
|
|
370
417
|
unlinkSync(tempFile);
|
|
371
418
|
}
|
|
372
419
|
}
|
|
373
420
|
catch (error) {
|
|
374
|
-
spinner
|
|
375
|
-
|
|
421
|
+
if (spinner)
|
|
422
|
+
spinner.fail('Failed to reply to comment');
|
|
423
|
+
if (!quiet)
|
|
424
|
+
console.error(error);
|
|
376
425
|
}
|
|
377
426
|
await this.jobManager.updateTaskStatus(task.uuid, 'completed');
|
|
378
427
|
continue;
|
|
379
428
|
}
|
|
380
429
|
// Create commit with co-author
|
|
381
|
-
|
|
430
|
+
if (!quiet)
|
|
431
|
+
spinner = ora('Creating commit...').start();
|
|
382
432
|
const commitMessage = `Address review comment from @${comment.author}
|
|
383
433
|
|
|
384
434
|
${comment.body.substring(0, 200)}${comment.body.length > 200 ? '...' : ''}
|
|
@@ -388,12 +438,14 @@ Co-authored-by: ivan-agent <ivan-agent@users.noreply.github.com}`;
|
|
|
388
438
|
throw new Error('GitManager not initialized');
|
|
389
439
|
}
|
|
390
440
|
// Try to commit, handling pre-commit hook failures
|
|
391
|
-
const commitResult = await this.tryCommitWithFixes(commitMessage, task, worktreePath || this.workingDir, spinner);
|
|
441
|
+
const commitResult = await this.tryCommitWithFixes(commitMessage, task, worktreePath || this.workingDir, spinner, quiet);
|
|
392
442
|
if (commitResult.succeeded) {
|
|
393
|
-
spinner
|
|
443
|
+
if (spinner)
|
|
444
|
+
spinner.succeed('Changes committed');
|
|
394
445
|
}
|
|
395
446
|
else {
|
|
396
|
-
spinner
|
|
447
|
+
if (spinner)
|
|
448
|
+
spinner.fail('Failed to commit after multiple attempts');
|
|
397
449
|
throw new Error('Pre-commit hook failures could not be fixed');
|
|
398
450
|
}
|
|
399
451
|
// Get the commit hash
|
|
@@ -404,20 +456,25 @@ Co-authored-by: ivan-agent <ivan-agent@users.noreply.github.com}`;
|
|
|
404
456
|
// Save commit hash to task
|
|
405
457
|
await this.jobManager.updateTaskCommit(task.uuid, commitHash);
|
|
406
458
|
// Push the commit immediately
|
|
407
|
-
|
|
459
|
+
if (!quiet)
|
|
460
|
+
spinner = ora('Pushing commit...').start();
|
|
408
461
|
try {
|
|
409
462
|
if (!this.gitManager) {
|
|
410
463
|
throw new Error('GitManager not initialized');
|
|
411
464
|
}
|
|
412
465
|
await this.gitManager.pushBranch(branch);
|
|
413
|
-
spinner
|
|
466
|
+
if (spinner)
|
|
467
|
+
spinner.succeed('Commit pushed successfully');
|
|
414
468
|
}
|
|
415
469
|
catch (error) {
|
|
416
|
-
spinner
|
|
417
|
-
|
|
470
|
+
if (spinner)
|
|
471
|
+
spinner.fail('Failed to push commit');
|
|
472
|
+
if (!quiet)
|
|
473
|
+
console.error(error);
|
|
418
474
|
}
|
|
419
475
|
// Reply to the comment with the fix
|
|
420
|
-
|
|
476
|
+
if (!quiet)
|
|
477
|
+
spinner = ora('Replying to comment...').start();
|
|
421
478
|
try {
|
|
422
479
|
// Truncate the message if it's too long (GitHub has a 65536 character limit)
|
|
423
480
|
const maxLength = 60000;
|
|
@@ -488,17 +545,22 @@ Co-authored-by: ivan-agent <ivan-agent@users.noreply.github.com}`;
|
|
|
488
545
|
cwd: worktreePath || this.workingDir,
|
|
489
546
|
stdio: 'pipe'
|
|
490
547
|
});
|
|
491
|
-
spinner
|
|
548
|
+
if (spinner)
|
|
549
|
+
spinner.succeed('Reply added to comment');
|
|
492
550
|
}
|
|
493
551
|
catch (error) {
|
|
494
|
-
spinner
|
|
495
|
-
|
|
552
|
+
if (spinner)
|
|
553
|
+
spinner.fail('Failed to reply to comment');
|
|
554
|
+
if (!quiet)
|
|
555
|
+
console.error(error);
|
|
496
556
|
}
|
|
497
557
|
await this.jobManager.updateTaskStatus(task.uuid, 'completed');
|
|
498
558
|
}
|
|
499
559
|
catch (error) {
|
|
500
|
-
spinner
|
|
501
|
-
|
|
560
|
+
if (spinner)
|
|
561
|
+
spinner.fail('Failed to address comment');
|
|
562
|
+
if (!quiet)
|
|
563
|
+
console.error(error);
|
|
502
564
|
const errorLog = error instanceof Error ? error.message : String(error);
|
|
503
565
|
await this.jobManager.updateTaskExecutionLog(task.uuid, `ERROR: ${errorLog}`);
|
|
504
566
|
await this.jobManager.updateTaskStatus(task.uuid, 'not_started');
|
|
@@ -506,7 +568,8 @@ Co-authored-by: ivan-agent <ivan-agent@users.noreply.github.com}`;
|
|
|
506
568
|
}
|
|
507
569
|
// Generate and add specific review comment (only if we have a PR number and made changes)
|
|
508
570
|
if (prNumber && (addressTasks.length > 0 || lintAndTestTasks.length > 0)) {
|
|
509
|
-
|
|
571
|
+
if (!quiet)
|
|
572
|
+
spinner = ora('Generating review request...').start();
|
|
510
573
|
try {
|
|
511
574
|
// Get the latest commit changes
|
|
512
575
|
const latestCommit = execSync('git rev-parse HEAD', {
|
|
@@ -523,20 +586,25 @@ Co-authored-by: ivan-agent <ivan-agent@users.noreply.github.com}`;
|
|
|
523
586
|
}).trim().split('\n').filter(Boolean);
|
|
524
587
|
// Generate specific review instructions using OpenAI
|
|
525
588
|
const reviewInstructions = await this.generateReviewInstructions(commitDiff, changedFiles, parseInt(prNumber));
|
|
526
|
-
spinner
|
|
589
|
+
if (spinner)
|
|
590
|
+
spinner.succeed('Review request generated');
|
|
527
591
|
// Add the review comment
|
|
528
|
-
|
|
592
|
+
if (!quiet)
|
|
593
|
+
spinner = ora('Adding review request comment...').start();
|
|
529
594
|
const reviewAgent = this.configManager.getReviewAgent();
|
|
530
595
|
const reviewComment = `${reviewAgent} ${reviewInstructions}`;
|
|
531
596
|
execSync(`gh pr comment ${prNumber} --body "${reviewComment.replace(/"/g, '\\"')}"`, {
|
|
532
597
|
cwd: worktreePath || this.workingDir,
|
|
533
598
|
stdio: 'pipe'
|
|
534
599
|
});
|
|
535
|
-
spinner
|
|
600
|
+
if (spinner)
|
|
601
|
+
spinner.succeed('Review request comment added');
|
|
536
602
|
}
|
|
537
603
|
catch (error) {
|
|
538
|
-
spinner
|
|
539
|
-
|
|
604
|
+
if (spinner)
|
|
605
|
+
spinner.fail('Failed to add review comment');
|
|
606
|
+
if (!quiet)
|
|
607
|
+
console.error(error);
|
|
540
608
|
}
|
|
541
609
|
}
|
|
542
610
|
// Clean up worktree after processing branch
|
|
@@ -546,15 +614,19 @@ Co-authored-by: ivan-agent <ivan-agent@users.noreply.github.com}`;
|
|
|
546
614
|
await this.gitManager.removeWorktree(branch);
|
|
547
615
|
}
|
|
548
616
|
catch (error) {
|
|
549
|
-
|
|
617
|
+
if (!quiet)
|
|
618
|
+
console.log(chalk.yellow(`⚠️ Could not clean up worktree: ${error}`));
|
|
550
619
|
}
|
|
551
620
|
}
|
|
552
621
|
}
|
|
553
|
-
|
|
554
|
-
|
|
622
|
+
if (!quiet) {
|
|
623
|
+
console.log('');
|
|
624
|
+
console.log(chalk.green.bold('🎉 All address tasks completed!'));
|
|
625
|
+
}
|
|
555
626
|
}
|
|
556
627
|
catch (error) {
|
|
557
|
-
|
|
628
|
+
if (!quiet)
|
|
629
|
+
console.error(chalk.red.bold('❌ Address workflow failed:'), error);
|
|
558
630
|
throw error;
|
|
559
631
|
}
|
|
560
632
|
}
|
|
@@ -681,7 +753,7 @@ Return ONLY the review request text, without any prefix like "Please review" sin
|
|
|
681
753
|
return 'please review the latest changes and verify all review comments have been properly addressed';
|
|
682
754
|
}
|
|
683
755
|
}
|
|
684
|
-
async tryCommitWithFixes(commitMessage, task, workingDir, spinner) {
|
|
756
|
+
async tryCommitWithFixes(commitMessage, task, workingDir, spinner, quiet = false) {
|
|
685
757
|
let commitAttempts = 0;
|
|
686
758
|
const maxCommitAttempts = 3;
|
|
687
759
|
let commitSucceeded = false;
|
|
@@ -693,7 +765,7 @@ Return ONLY the review request text, without any prefix like "Please review" sin
|
|
|
693
765
|
await this.gitManager.commitChanges(commitMessage);
|
|
694
766
|
commitSucceeded = true;
|
|
695
767
|
// Stop the spinner if we're retrying
|
|
696
|
-
if (commitAttempts > 0 && spinner.isSpinning) {
|
|
768
|
+
if (commitAttempts > 0 && spinner && spinner.isSpinning) {
|
|
697
769
|
spinner.succeed('Commit successful after retry');
|
|
698
770
|
}
|
|
699
771
|
}
|
|
@@ -702,26 +774,33 @@ Return ONLY the review request text, without any prefix like "Please review" sin
|
|
|
702
774
|
const errorMessage = commitError instanceof Error ? commitError.message : String(commitError);
|
|
703
775
|
// Check if this is a pre-commit hook failure
|
|
704
776
|
if (errorMessage.includes('pre-commit') && commitAttempts < maxCommitAttempts) {
|
|
705
|
-
|
|
706
|
-
|
|
777
|
+
if (spinner) {
|
|
778
|
+
spinner.fail(`Pre-commit hook failed (attempt ${commitAttempts}/${maxCommitAttempts})`);
|
|
779
|
+
console.log(chalk.yellow('🔧 Running Claude to fix pre-commit errors...'));
|
|
780
|
+
}
|
|
707
781
|
// Extract the error details from the commit error
|
|
708
782
|
const errorDetails = errorMessage;
|
|
709
783
|
// Prepare prompt for Claude to fix the errors
|
|
710
784
|
const fixPrompt = `Fix the following pre-commit hook errors:\n\n${errorDetails}\n\nPlease fix all TypeScript errors, linting issues, and any other problems preventing the commit.`;
|
|
711
|
-
|
|
785
|
+
if (!quiet)
|
|
786
|
+
spinner = ora('Running Claude to fix pre-commit errors...').start();
|
|
712
787
|
try {
|
|
713
788
|
// Run Claude to fix the errors
|
|
714
789
|
const fixResult = await this.getClaudeExecutor().executeTask(fixPrompt, workingDir);
|
|
715
|
-
spinner
|
|
790
|
+
if (spinner)
|
|
791
|
+
spinner.succeed('Claude attempted to fix the errors');
|
|
716
792
|
// Update the execution log with the fix attempt
|
|
717
793
|
const previousLog = await this.jobManager.getTaskExecutionLog(task.uuid);
|
|
718
794
|
await this.jobManager.updateTaskExecutionLog(task.uuid, `${previousLog}\n\n--- Pre-commit Fix Attempt ${commitAttempts} ---\n${fixResult.log}`);
|
|
719
795
|
// Try to commit again on the next iteration
|
|
720
|
-
|
|
796
|
+
if (!quiet)
|
|
797
|
+
spinner = ora('Retrying commit...').start();
|
|
721
798
|
}
|
|
722
799
|
catch (fixError) {
|
|
723
|
-
spinner
|
|
724
|
-
|
|
800
|
+
if (spinner)
|
|
801
|
+
spinner.fail('Failed to run Claude to fix errors');
|
|
802
|
+
if (!quiet)
|
|
803
|
+
console.error(chalk.red('Claude fix attempt failed:'), fixError);
|
|
725
804
|
throw commitError; // Re-throw the original error
|
|
726
805
|
}
|
|
727
806
|
}
|