@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.
Files changed (32) hide show
  1. package/dist/services/address-task-executor.d.ts +1 -1
  2. package/dist/services/address-task-executor.d.ts.map +1 -1
  3. package/dist/services/address-task-executor.js +163 -84
  4. package/dist/services/address-task-executor.js.map +1 -1
  5. package/dist/services/claude-cli-executor.d.ts +1 -0
  6. package/dist/services/claude-cli-executor.d.ts.map +1 -1
  7. package/dist/services/claude-cli-executor.js +5 -0
  8. package/dist/services/claude-cli-executor.js.map +1 -1
  9. package/dist/services/claude-executor.d.ts +1 -0
  10. package/dist/services/claude-executor.d.ts.map +1 -1
  11. package/dist/services/claude-executor.js +27 -14
  12. package/dist/services/claude-executor.js.map +1 -1
  13. package/dist/services/executor-factory.d.ts +1 -0
  14. package/dist/services/executor-factory.d.ts.map +1 -1
  15. package/dist/services/executor-factory.js.map +1 -1
  16. package/dist/services/git-interfaces.d.ts +1 -0
  17. package/dist/services/git-interfaces.d.ts.map +1 -1
  18. package/dist/services/git-manager-cli.d.ts +1 -0
  19. package/dist/services/git-manager-cli.d.ts.map +1 -1
  20. package/dist/services/git-manager-cli.js +1 -0
  21. package/dist/services/git-manager-cli.js.map +1 -1
  22. package/dist/services/git-manager-pat.d.ts +1 -0
  23. package/dist/services/git-manager-pat.d.ts.map +1 -1
  24. package/dist/services/git-manager-pat.js +64 -32
  25. package/dist/services/git-manager-pat.js.map +1 -1
  26. package/dist/services/github-api-client.d.ts.map +1 -1
  27. package/dist/services/github-api-client.js +22 -5
  28. package/dist/services/github-api-client.js.map +1 -1
  29. package/dist/services/task-executor.d.ts.map +1 -1
  30. package/dist/services/task-executor.js +177 -145
  31. package/dist/services/task-executor.js.map +1 -1
  32. 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;YA6oBzC,sBAAsB;YAwGtB,0BAA0B;YAyD1B,kBAAkB;CAoEjC"}
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
- console.log(chalk.blue.bold('🚀 Starting address task workflow'));
38
- console.log('');
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
- console.log(chalk.green('✅ Claude Code SDK configured'));
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
- console.log(chalk.green('✅ GitHub CLI is installed'));
59
+ if (!quiet)
60
+ console.log(chalk.green('✅ GitHub CLI is installed'));
57
61
  this.gitManager.validateGitHubCliAuthentication();
58
- console.log(chalk.green('✅ GitHub CLI is authenticated'));
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
- console.log(chalk.yellow('⚠️ Skipping tasks without branch information'));
81
+ if (!quiet)
82
+ console.log(chalk.yellow('⚠️ Skipping tasks without branch information'));
77
83
  continue;
78
84
  }
79
- console.log('');
80
- console.log(chalk.cyan.bold(`🔄 Creating worktree for branch: ${branch}`));
81
- let spinner = ora('Creating worktree...').start();
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.succeed(`Worktree created: ${worktreePath}`);
98
+ if (spinner)
99
+ spinner.succeed(`Worktree created: ${worktreePath}`);
91
100
  }
92
101
  catch (error) {
93
- spinner.fail(`Failed to create worktree for branch: ${branch}`);
94
- console.error(error);
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
- console.log('');
103
- console.log(chalk.blue('🔧 Fixing test and lint failures'));
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
- spinner = ora('Fetching GitHub Actions logs...').start();
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 (actionLogs) {
114
- spinner.succeed('GitHub Actions logs fetched');
115
- }
116
- else {
117
- spinner.info('No failing action logs found');
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.warn('Could not fetch GitHub Actions logs');
122
- console.error(error);
137
+ if (spinner)
138
+ spinner.warn('Could not fetch GitHub Actions logs');
139
+ if (!quiet)
140
+ console.error(error);
123
141
  }
124
142
  }
125
- spinner = ora('Running Claude Code to fix test and lint failures...').start();
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.succeed('Claude Code execution completed');
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
- console.log(chalk.yellow('⚠️ No changes made'));
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
- spinner = ora('Creating commit...').start();
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.succeed('Changes committed');
185
+ if (spinner)
186
+ spinner.succeed('Changes committed');
164
187
  }
165
188
  else {
166
- spinner.fail('Failed to commit after multiple attempts');
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
- spinner = ora('Pushing commit...').start();
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.succeed('Commit pushed successfully');
208
+ if (spinner)
209
+ spinner.succeed('Commit pushed successfully');
184
210
  }
185
211
  catch (error) {
186
- spinner.fail('Failed to push commit');
187
- console.error(error);
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
- spinner = ora('Adding review request comment...').start();
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.succeed('Review request comment added');
228
+ if (spinner)
229
+ spinner.succeed('Review request comment added');
200
230
  }
201
231
  catch (error) {
202
- spinner.fail('Failed to add review comment');
203
- console.error(error);
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.fail('Failed to fix test and lint failures');
210
- console.error(error);
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
- spinner = ora('Fetching PR comments...').start();
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.succeed(`Found ${comments.length} unaddressed comments`);
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
- console.log(chalk.yellow('⚠️ No unaddressed comments found'));
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
- console.log(chalk.yellow('⚠️ No task found for this comment'));
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
- spinner = ora('Running Claude Code to address comment...').start();
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.succeed('Claude Code execution completed');
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
- console.log(chalk.yellow('⚠️ No changes made - Claude determined no changes were needed'));
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
- spinner = ora('Replying to comment...').start();
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.succeed('Reply added to comment');
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.fail('Failed to reply to comment');
375
- console.error(error);
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
- spinner = ora('Creating commit...').start();
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.succeed('Changes committed');
443
+ if (spinner)
444
+ spinner.succeed('Changes committed');
394
445
  }
395
446
  else {
396
- spinner.fail('Failed to commit after multiple attempts');
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
- spinner = ora('Pushing commit...').start();
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.succeed('Commit pushed successfully');
466
+ if (spinner)
467
+ spinner.succeed('Commit pushed successfully');
414
468
  }
415
469
  catch (error) {
416
- spinner.fail('Failed to push commit');
417
- console.error(error);
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
- spinner = ora('Replying to comment...').start();
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.succeed('Reply added to comment');
548
+ if (spinner)
549
+ spinner.succeed('Reply added to comment');
492
550
  }
493
551
  catch (error) {
494
- spinner.fail('Failed to reply to comment');
495
- console.error(error);
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.fail('Failed to address comment');
501
- console.error(error);
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
- spinner = ora('Generating review request...').start();
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.succeed('Review request generated');
589
+ if (spinner)
590
+ spinner.succeed('Review request generated');
527
591
  // Add the review comment
528
- spinner = ora('Adding review request comment...').start();
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.succeed('Review request comment added');
600
+ if (spinner)
601
+ spinner.succeed('Review request comment added');
536
602
  }
537
603
  catch (error) {
538
- spinner.fail('Failed to add review comment');
539
- console.error(error);
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
- console.log(chalk.yellow(`⚠️ Could not clean up worktree: ${error}`));
617
+ if (!quiet)
618
+ console.log(chalk.yellow(`⚠️ Could not clean up worktree: ${error}`));
550
619
  }
551
620
  }
552
621
  }
553
- console.log('');
554
- console.log(chalk.green.bold('🎉 All address tasks completed!'));
622
+ if (!quiet) {
623
+ console.log('');
624
+ console.log(chalk.green.bold('🎉 All address tasks completed!'));
625
+ }
555
626
  }
556
627
  catch (error) {
557
- console.error(chalk.red.bold('❌ Address workflow failed:'), error);
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
- spinner.fail(`Pre-commit hook failed (attempt ${commitAttempts}/${maxCommitAttempts})`);
706
- console.log(chalk.yellow('🔧 Running Claude to fix pre-commit errors...'));
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
- spinner = ora('Running Claude to fix pre-commit errors...').start();
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.succeed('Claude attempted to fix the errors');
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
- spinner = ora('Retrying commit...').start();
796
+ if (!quiet)
797
+ spinner = ora('Retrying commit...').start();
721
798
  }
722
799
  catch (fixError) {
723
- spinner.fail('Failed to run Claude to fix errors');
724
- console.error(chalk.red('Claude fix attempt failed:'), fixError);
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
  }