@ariso-ai/ivan 1.0.11 → 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 +1 -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 +26 -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
|
@@ -236,31 +236,39 @@ export class TaskExecutor {
|
|
|
236
236
|
}
|
|
237
237
|
return addressTasks;
|
|
238
238
|
}
|
|
239
|
-
async executeTask(task) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
async executeTask(task, quiet = false) {
|
|
240
|
+
if (!quiet) {
|
|
241
|
+
console.log('');
|
|
242
|
+
console.log(chalk.cyan.bold(`📝 Task: ${task.description}`));
|
|
243
|
+
}
|
|
244
|
+
let spinner = quiet ? null : ora('Updating task status...').start();
|
|
243
245
|
let worktreePath = null;
|
|
244
246
|
let branchName = null;
|
|
245
247
|
try {
|
|
246
248
|
await this.jobManager.updateTaskStatus(task.uuid, 'active');
|
|
247
|
-
spinner
|
|
248
|
-
|
|
249
|
+
if (spinner)
|
|
250
|
+
spinner.succeed('Task marked as active');
|
|
251
|
+
if (!quiet)
|
|
252
|
+
spinner = ora('Cleaning up and syncing with main branch...').start();
|
|
249
253
|
if (!this.gitManager) {
|
|
250
254
|
throw new Error('GitManager not initialized');
|
|
251
255
|
}
|
|
252
256
|
await this.gitManager.cleanupAndSyncMain();
|
|
253
|
-
spinner
|
|
257
|
+
if (spinner)
|
|
258
|
+
spinner.succeed('Repository cleaned and synced with main');
|
|
254
259
|
if (!this.gitManager) {
|
|
255
260
|
throw new Error('GitManager not initialized');
|
|
256
261
|
}
|
|
257
262
|
branchName = this.gitManager.generateBranchName(task.description);
|
|
258
|
-
|
|
263
|
+
if (!quiet)
|
|
264
|
+
spinner = ora(`Creating worktree for branch: ${branchName}`).start();
|
|
259
265
|
worktreePath = await this.gitManager.createWorktree(branchName);
|
|
260
266
|
this.gitManager.switchToWorktree(worktreePath);
|
|
261
|
-
spinner
|
|
267
|
+
if (spinner)
|
|
268
|
+
spinner.succeed(`Worktree created: ${worktreePath}`);
|
|
262
269
|
await this.jobManager.updateTaskBranch(task.uuid, branchName);
|
|
263
|
-
|
|
270
|
+
if (!quiet)
|
|
271
|
+
spinner = ora('Executing task with Claude Code...').start();
|
|
264
272
|
// Append repository-specific instructions to the task if they exist
|
|
265
273
|
let taskWithInstructions = task.description;
|
|
266
274
|
if (this.repoInstructions) {
|
|
@@ -269,16 +277,25 @@ export class TaskExecutor {
|
|
|
269
277
|
// Use worktree path for Claude execution, falling back to workingDir if needed
|
|
270
278
|
const executionPath = worktreePath || this.workingDir;
|
|
271
279
|
const result = await this.getClaudeExecutor().executeTask(taskWithInstructions, executionPath);
|
|
272
|
-
spinner
|
|
273
|
-
|
|
280
|
+
if (spinner) {
|
|
281
|
+
spinner.succeed('Claude Code execution completed');
|
|
282
|
+
}
|
|
283
|
+
else if (quiet) {
|
|
284
|
+
// In quiet mode, output the final message from Claude
|
|
285
|
+
console.log(result.lastMessage);
|
|
286
|
+
}
|
|
287
|
+
if (!quiet)
|
|
288
|
+
spinner = ora('Storing execution log...').start();
|
|
274
289
|
await this.jobManager.updateTaskExecutionLog(task.uuid, result.log);
|
|
275
|
-
spinner
|
|
290
|
+
if (spinner)
|
|
291
|
+
spinner.succeed('Execution log stored');
|
|
276
292
|
if (!this.gitManager) {
|
|
277
293
|
throw new Error('GitManager not initialized');
|
|
278
294
|
}
|
|
279
295
|
const changedFiles = this.gitManager.getChangedFiles();
|
|
280
296
|
if (changedFiles.length === 0) {
|
|
281
|
-
|
|
297
|
+
if (!quiet)
|
|
298
|
+
console.log(chalk.yellow('⚠️ No changes detected, skipping commit and PR creation'));
|
|
282
299
|
await this.jobManager.updateTaskStatus(task.uuid, 'completed');
|
|
283
300
|
return;
|
|
284
301
|
}
|
|
@@ -286,10 +303,13 @@ export class TaskExecutor {
|
|
|
286
303
|
throw new Error('GitManager not initialized');
|
|
287
304
|
}
|
|
288
305
|
const diff = this.gitManager.getDiff();
|
|
289
|
-
|
|
306
|
+
if (!quiet)
|
|
307
|
+
spinner = ora('Generating commit message...').start();
|
|
290
308
|
const commitMessage = await this.getOpenAIService().generateCommitMessage(diff, changedFiles);
|
|
291
|
-
spinner
|
|
292
|
-
|
|
309
|
+
if (spinner)
|
|
310
|
+
spinner.succeed(`Commit message generated: ${commitMessage}`);
|
|
311
|
+
if (!quiet)
|
|
312
|
+
spinner = ora('Committing changes...').start();
|
|
293
313
|
if (!this.gitManager) {
|
|
294
314
|
throw new Error('GitManager not initialized');
|
|
295
315
|
}
|
|
@@ -301,11 +321,13 @@ export class TaskExecutor {
|
|
|
301
321
|
try {
|
|
302
322
|
await this.gitManager.commitChanges(commitMessage);
|
|
303
323
|
// Only show success message if spinner is running (first attempt)
|
|
304
|
-
if (
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
spinner.
|
|
324
|
+
if (spinner) {
|
|
325
|
+
if (commitAttempts === 0) {
|
|
326
|
+
spinner.succeed('Changes committed');
|
|
327
|
+
}
|
|
328
|
+
else if (spinner.isSpinning) {
|
|
329
|
+
spinner.succeed('Commit successful after retry');
|
|
330
|
+
}
|
|
309
331
|
}
|
|
310
332
|
commitSucceeded = true;
|
|
311
333
|
}
|
|
@@ -314,26 +336,33 @@ export class TaskExecutor {
|
|
|
314
336
|
const errorMessage = commitError instanceof Error ? commitError.message : String(commitError);
|
|
315
337
|
// Check if this is a pre-commit hook failure
|
|
316
338
|
if (errorMessage.includes('pre-commit') && commitAttempts < maxCommitAttempts) {
|
|
317
|
-
|
|
318
|
-
|
|
339
|
+
if (spinner) {
|
|
340
|
+
spinner.fail(`Pre-commit hook failed (attempt ${commitAttempts}/${maxCommitAttempts})`);
|
|
341
|
+
console.log(chalk.yellow('🔧 Running Claude to fix pre-commit errors...'));
|
|
342
|
+
}
|
|
319
343
|
// Extract the error details from the commit error
|
|
320
344
|
const errorDetails = errorMessage;
|
|
321
345
|
// Prepare prompt for Claude to fix the errors
|
|
322
346
|
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.`;
|
|
323
|
-
|
|
347
|
+
if (!quiet)
|
|
348
|
+
spinner = ora('Running Claude to fix pre-commit errors...').start();
|
|
324
349
|
try {
|
|
325
350
|
// Run Claude to fix the errors
|
|
326
351
|
const fixResult = await this.getClaudeExecutor().executeTask(fixPrompt, worktreePath || this.workingDir);
|
|
327
|
-
spinner
|
|
352
|
+
if (spinner)
|
|
353
|
+
spinner.succeed('Claude attempted to fix the errors');
|
|
328
354
|
// Update the execution log with the fix attempt
|
|
329
355
|
const previousLog = await this.jobManager.getTaskExecutionLog(task.uuid);
|
|
330
356
|
await this.jobManager.updateTaskExecutionLog(task.uuid, `${previousLog}\n\n--- Pre-commit Fix Attempt ${commitAttempts} ---\n${fixResult.log}`);
|
|
331
357
|
// Try to commit again on the next iteration
|
|
332
|
-
|
|
358
|
+
if (!quiet)
|
|
359
|
+
spinner = ora('Retrying commit...').start();
|
|
333
360
|
}
|
|
334
361
|
catch (fixError) {
|
|
335
|
-
spinner
|
|
336
|
-
|
|
362
|
+
if (spinner)
|
|
363
|
+
spinner.fail('Failed to run Claude to fix errors');
|
|
364
|
+
if (!quiet)
|
|
365
|
+
console.error(chalk.red('Claude fix attempt failed:'), fixError);
|
|
337
366
|
throw commitError; // Re-throw the original error
|
|
338
367
|
}
|
|
339
368
|
}
|
|
@@ -346,40 +375,51 @@ export class TaskExecutor {
|
|
|
346
375
|
if (!commitSucceeded) {
|
|
347
376
|
throw new Error(`Failed to commit after ${maxCommitAttempts} attempts due to pre-commit hook failures`);
|
|
348
377
|
}
|
|
349
|
-
|
|
378
|
+
if (!quiet)
|
|
379
|
+
spinner = ora('Pushing branch...').start();
|
|
350
380
|
if (!this.gitManager) {
|
|
351
381
|
throw new Error('GitManager not initialized');
|
|
352
382
|
}
|
|
353
383
|
await this.gitManager.pushBranch(branchName);
|
|
354
|
-
spinner
|
|
355
|
-
|
|
384
|
+
if (spinner)
|
|
385
|
+
spinner.succeed('Branch pushed to origin');
|
|
386
|
+
if (!quiet)
|
|
387
|
+
spinner = ora('Generating PR description...').start();
|
|
356
388
|
const { title, body } = await this.getOpenAIService().generatePullRequestDescription(task.description, diff, changedFiles);
|
|
357
|
-
spinner
|
|
358
|
-
|
|
389
|
+
if (spinner)
|
|
390
|
+
spinner.succeed('PR description generated');
|
|
391
|
+
if (!quiet)
|
|
392
|
+
spinner = ora('Creating pull request...').start();
|
|
359
393
|
if (!this.gitManager) {
|
|
360
394
|
throw new Error('GitManager not initialized');
|
|
361
395
|
}
|
|
362
396
|
const prUrl = await this.gitManager.createPullRequest(title, body);
|
|
363
|
-
spinner
|
|
397
|
+
if (spinner)
|
|
398
|
+
spinner.succeed(`Pull request created: ${prUrl}`);
|
|
364
399
|
await this.jobManager.updateTaskPrLink(task.uuid, prUrl);
|
|
365
400
|
await this.jobManager.updateTaskStatus(task.uuid, 'completed');
|
|
366
|
-
|
|
367
|
-
|
|
401
|
+
if (!quiet) {
|
|
402
|
+
console.log(chalk.green(`✅ Task completed: ${task.description}`));
|
|
403
|
+
console.log(chalk.cyan(`🔗 PR: ${prUrl}`));
|
|
404
|
+
}
|
|
368
405
|
}
|
|
369
406
|
catch (error) {
|
|
370
|
-
if (spinner.isSpinning) {
|
|
407
|
+
if (spinner && spinner.isSpinning) {
|
|
371
408
|
spinner.fail('Task execution failed');
|
|
372
409
|
}
|
|
373
410
|
// Store error log if execution failed
|
|
374
411
|
try {
|
|
375
412
|
const errorLog = error instanceof Error ? error.message : String(error);
|
|
376
413
|
await this.jobManager.updateTaskExecutionLog(task.uuid, `ERROR: ${errorLog}`);
|
|
377
|
-
|
|
414
|
+
if (!quiet)
|
|
415
|
+
console.log(chalk.gray('Error log stored to database'));
|
|
378
416
|
}
|
|
379
417
|
catch (logError) {
|
|
380
|
-
|
|
418
|
+
if (!quiet)
|
|
419
|
+
console.error(chalk.red('Failed to store error log:'), logError);
|
|
381
420
|
}
|
|
382
|
-
|
|
421
|
+
if (!quiet)
|
|
422
|
+
console.error(chalk.red(`❌ Failed to execute task: ${task.description}`), error);
|
|
383
423
|
throw error;
|
|
384
424
|
}
|
|
385
425
|
finally {
|
|
@@ -390,10 +430,12 @@ export class TaskExecutor {
|
|
|
390
430
|
}
|
|
391
431
|
}
|
|
392
432
|
}
|
|
393
|
-
async executeTasksWithSinglePR(tasks) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
433
|
+
async executeTasksWithSinglePR(tasks, quiet = false) {
|
|
434
|
+
if (!quiet) {
|
|
435
|
+
console.log('');
|
|
436
|
+
console.log(chalk.blue('📦 Creating single branch for all tasks...'));
|
|
437
|
+
}
|
|
438
|
+
let spinner = quiet ? null : ora('Cleaning up and syncing with main branch...').start();
|
|
397
439
|
let worktreePath = null;
|
|
398
440
|
let branchName = null;
|
|
399
441
|
let sessionId;
|
|
@@ -402,16 +444,19 @@ export class TaskExecutor {
|
|
|
402
444
|
throw new Error('GitManager not initialized');
|
|
403
445
|
}
|
|
404
446
|
await this.gitManager.cleanupAndSyncMain();
|
|
405
|
-
spinner
|
|
447
|
+
if (spinner)
|
|
448
|
+
spinner.succeed('Repository cleaned and synced with main');
|
|
406
449
|
// Generate branch name based on all tasks
|
|
407
450
|
const combinedDescription = tasks.length === 1
|
|
408
451
|
? tasks[0].description
|
|
409
452
|
: `Multiple tasks: ${tasks.slice(0, 2).map(t => t.description).join(', ')}${tasks.length > 2 ? '...' : ''}`;
|
|
410
453
|
branchName = this.gitManager.generateBranchName(combinedDescription);
|
|
411
|
-
|
|
454
|
+
if (!quiet)
|
|
455
|
+
spinner = ora(`Creating worktree for branch: ${branchName}`).start();
|
|
412
456
|
worktreePath = await this.gitManager.createWorktree(branchName);
|
|
413
457
|
this.gitManager.switchToWorktree(worktreePath);
|
|
414
|
-
spinner
|
|
458
|
+
if (spinner)
|
|
459
|
+
spinner.succeed(`Worktree created: ${worktreePath}`);
|
|
415
460
|
// Update all tasks with the same branch
|
|
416
461
|
for (const task of tasks) {
|
|
417
462
|
await this.jobManager.updateTaskBranch(task.uuid, branchName);
|
|
@@ -419,12 +464,17 @@ export class TaskExecutor {
|
|
|
419
464
|
// Execute each task on the same branch
|
|
420
465
|
for (let i = 0; i < tasks.length; i++) {
|
|
421
466
|
const task = tasks[i];
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
467
|
+
if (!quiet) {
|
|
468
|
+
console.log('');
|
|
469
|
+
console.log(chalk.cyan.bold(`📝 Task ${i + 1}/${tasks.length}: ${task.description}`));
|
|
470
|
+
}
|
|
471
|
+
if (!quiet)
|
|
472
|
+
spinner = ora('Updating task status...').start();
|
|
425
473
|
await this.jobManager.updateTaskStatus(task.uuid, 'active');
|
|
426
|
-
spinner
|
|
427
|
-
|
|
474
|
+
if (spinner)
|
|
475
|
+
spinner.succeed('Task marked as active');
|
|
476
|
+
if (!quiet)
|
|
477
|
+
spinner = ora('Executing task with Claude Code...').start();
|
|
428
478
|
// Append repository-specific instructions to the task if they exist
|
|
429
479
|
let taskWithInstructions = task.description;
|
|
430
480
|
if (this.repoInstructions) {
|
|
@@ -436,10 +486,18 @@ export class TaskExecutor {
|
|
|
436
486
|
const result = await this.getClaudeExecutor().executeTask(taskWithInstructions, executionPath, sessionId);
|
|
437
487
|
// Store the session ID for the next task
|
|
438
488
|
sessionId = result.sessionId;
|
|
439
|
-
spinner
|
|
440
|
-
|
|
489
|
+
if (spinner) {
|
|
490
|
+
spinner.succeed('Claude Code execution completed');
|
|
491
|
+
}
|
|
492
|
+
else if (quiet) {
|
|
493
|
+
// In quiet mode, output the final message from Claude
|
|
494
|
+
console.log(result.lastMessage);
|
|
495
|
+
}
|
|
496
|
+
if (!quiet)
|
|
497
|
+
spinner = ora('Storing execution log...').start();
|
|
441
498
|
await this.jobManager.updateTaskExecutionLog(task.uuid, result.log);
|
|
442
|
-
spinner
|
|
499
|
+
if (spinner)
|
|
500
|
+
spinner.succeed('Execution log stored');
|
|
443
501
|
// Commit changes after each task (but don't create PR yet)
|
|
444
502
|
if (!this.gitManager) {
|
|
445
503
|
throw new Error('GitManager not initialized');
|
|
@@ -447,10 +505,13 @@ export class TaskExecutor {
|
|
|
447
505
|
const changedFiles = this.gitManager.getChangedFiles();
|
|
448
506
|
if (changedFiles.length > 0) {
|
|
449
507
|
const diff = this.gitManager.getDiff();
|
|
450
|
-
|
|
508
|
+
if (!quiet)
|
|
509
|
+
spinner = ora('Generating commit message...').start();
|
|
451
510
|
const commitMessage = await this.getOpenAIService().generateCommitMessage(diff, changedFiles);
|
|
452
|
-
spinner
|
|
453
|
-
|
|
511
|
+
if (spinner)
|
|
512
|
+
spinner.succeed(`Commit message generated: ${commitMessage}`);
|
|
513
|
+
if (!quiet)
|
|
514
|
+
spinner = ora('Committing changes...').start();
|
|
454
515
|
// Try to commit, handling pre-commit hook failures
|
|
455
516
|
let commitAttempts = 0;
|
|
456
517
|
const maxCommitAttempts = 3;
|
|
@@ -459,11 +520,13 @@ export class TaskExecutor {
|
|
|
459
520
|
try {
|
|
460
521
|
await this.gitManager.commitChanges(commitMessage);
|
|
461
522
|
// Only show success message if spinner is running (first attempt)
|
|
462
|
-
if (
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
spinner.
|
|
523
|
+
if (spinner) {
|
|
524
|
+
if (commitAttempts === 0) {
|
|
525
|
+
spinner.succeed('Changes committed');
|
|
526
|
+
}
|
|
527
|
+
else if (spinner.isSpinning) {
|
|
528
|
+
spinner.succeed('Commit successful after retry');
|
|
529
|
+
}
|
|
467
530
|
}
|
|
468
531
|
commitSucceeded = true;
|
|
469
532
|
}
|
|
@@ -472,28 +535,35 @@ export class TaskExecutor {
|
|
|
472
535
|
const errorMessage = commitError instanceof Error ? commitError.message : String(commitError);
|
|
473
536
|
// Check if this is a pre-commit hook failure
|
|
474
537
|
if (errorMessage.includes('pre-commit') && commitAttempts < maxCommitAttempts) {
|
|
475
|
-
|
|
476
|
-
|
|
538
|
+
if (spinner) {
|
|
539
|
+
spinner.fail(`Pre-commit hook failed (attempt ${commitAttempts}/${maxCommitAttempts})`);
|
|
540
|
+
console.log(chalk.yellow('🔧 Running Claude to fix pre-commit errors...'));
|
|
541
|
+
}
|
|
477
542
|
// Extract the error details from the commit error
|
|
478
543
|
const errorDetails = errorMessage;
|
|
479
544
|
// Prepare prompt for Claude to fix the errors
|
|
480
545
|
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.`;
|
|
481
|
-
|
|
546
|
+
if (!quiet)
|
|
547
|
+
spinner = ora('Running Claude to fix pre-commit errors...').start();
|
|
482
548
|
try {
|
|
483
549
|
// Run Claude to fix the errors (pass session ID to maintain context)
|
|
484
550
|
const fixResult = await this.getClaudeExecutor().executeTask(fixPrompt, executionPath, sessionId);
|
|
485
551
|
// Update session ID
|
|
486
552
|
sessionId = fixResult.sessionId;
|
|
487
|
-
spinner
|
|
553
|
+
if (spinner)
|
|
554
|
+
spinner.succeed('Claude attempted to fix the errors');
|
|
488
555
|
// Update the execution log with the fix attempt
|
|
489
556
|
const previousLog = await this.jobManager.getTaskExecutionLog(task.uuid);
|
|
490
557
|
await this.jobManager.updateTaskExecutionLog(task.uuid, `${previousLog}\n\n--- Pre-commit Fix Attempt ${commitAttempts} ---\n${fixResult.log}`);
|
|
491
558
|
// Try to commit again on the next iteration
|
|
492
|
-
|
|
559
|
+
if (!quiet)
|
|
560
|
+
spinner = ora('Retrying commit...').start();
|
|
493
561
|
}
|
|
494
562
|
catch (fixError) {
|
|
495
|
-
spinner
|
|
496
|
-
|
|
563
|
+
if (spinner)
|
|
564
|
+
spinner.fail('Failed to run Claude to fix errors');
|
|
565
|
+
if (!quiet)
|
|
566
|
+
console.error(chalk.red('Claude fix attempt failed:'), fixError);
|
|
497
567
|
throw commitError; // Re-throw the original error
|
|
498
568
|
}
|
|
499
569
|
}
|
|
@@ -508,43 +578,54 @@ export class TaskExecutor {
|
|
|
508
578
|
}
|
|
509
579
|
}
|
|
510
580
|
else {
|
|
511
|
-
|
|
581
|
+
if (!quiet)
|
|
582
|
+
console.log(chalk.yellow('⚠️ No changes detected for this task'));
|
|
512
583
|
}
|
|
513
584
|
await this.jobManager.updateTaskStatus(task.uuid, 'completed');
|
|
514
|
-
|
|
585
|
+
if (!quiet)
|
|
586
|
+
console.log(chalk.green(`✅ Task ${i + 1}/${tasks.length} completed`));
|
|
515
587
|
}
|
|
516
588
|
// After all tasks are complete, create a single PR
|
|
517
|
-
|
|
589
|
+
if (!quiet)
|
|
590
|
+
spinner = ora('Pushing branch...').start();
|
|
518
591
|
if (!this.gitManager) {
|
|
519
592
|
throw new Error('GitManager not initialized');
|
|
520
593
|
}
|
|
521
594
|
await this.gitManager.pushBranch(branchName);
|
|
522
|
-
spinner
|
|
595
|
+
if (spinner)
|
|
596
|
+
spinner.succeed('Branch pushed to origin');
|
|
523
597
|
// Generate PR description based on all tasks
|
|
524
|
-
|
|
598
|
+
if (!quiet)
|
|
599
|
+
spinner = ora('Generating pull request description...').start();
|
|
525
600
|
const allTaskDescriptions = tasks.map(t => `- ${t.description}`).join('\n');
|
|
526
601
|
const prTaskDescription = `Completed ${tasks.length} tasks:\n\n${allTaskDescriptions}`;
|
|
527
602
|
// Get combined diff for PR description
|
|
528
603
|
const finalDiff = this.gitManager.getDiff('origin/main', 'HEAD');
|
|
529
604
|
const allChangedFiles = this.gitManager.getChangedFiles('origin/main');
|
|
530
605
|
const { title, body } = await this.getOpenAIService().generatePullRequestDescription(prTaskDescription, finalDiff, allChangedFiles);
|
|
531
|
-
spinner
|
|
532
|
-
|
|
606
|
+
if (spinner)
|
|
607
|
+
spinner.succeed('PR description generated');
|
|
608
|
+
if (!quiet)
|
|
609
|
+
spinner = ora('Creating pull request...').start();
|
|
533
610
|
const prUrl = await this.gitManager.createPullRequest(title, body);
|
|
534
|
-
spinner
|
|
611
|
+
if (spinner)
|
|
612
|
+
spinner.succeed(`Pull request created: ${prUrl}`);
|
|
535
613
|
// Update all tasks with the same PR link
|
|
536
614
|
for (const task of tasks) {
|
|
537
615
|
await this.jobManager.updateTaskPrLink(task.uuid, prUrl);
|
|
538
616
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
617
|
+
if (!quiet) {
|
|
618
|
+
console.log('');
|
|
619
|
+
console.log(chalk.green.bold(`✅ All ${tasks.length} tasks completed in a single PR!`));
|
|
620
|
+
console.log(chalk.cyan(`🔗 PR: ${prUrl}`));
|
|
621
|
+
}
|
|
542
622
|
}
|
|
543
623
|
catch (error) {
|
|
544
624
|
if (spinner && spinner.isSpinning) {
|
|
545
625
|
spinner.fail('Batch task execution failed');
|
|
546
626
|
}
|
|
547
|
-
|
|
627
|
+
if (!quiet)
|
|
628
|
+
console.error(chalk.red('❌ Failed to execute tasks with single PR:'), error);
|
|
548
629
|
throw error;
|
|
549
630
|
}
|
|
550
631
|
finally {
|
|
@@ -557,49 +638,28 @@ export class TaskExecutor {
|
|
|
557
638
|
}
|
|
558
639
|
async executeNonInteractiveWorkflow(config) {
|
|
559
640
|
try {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
await
|
|
564
|
-
console.log(chalk.green('✅ Claude Code SDK configured'));
|
|
641
|
+
// Quiet mode: suppress all intermediate output
|
|
642
|
+
const executor = this.getClaudeExecutor();
|
|
643
|
+
executor.quietMode = true;
|
|
644
|
+
await executor.validateClaudeCodeInstallation();
|
|
565
645
|
this.workingDir = await this.repositoryManager.getValidWorkingDirectory();
|
|
566
646
|
this.gitManager = createGitManager(this.workingDir);
|
|
567
647
|
if (!this.gitManager) {
|
|
568
648
|
throw new Error('GitManager not initialized');
|
|
569
649
|
}
|
|
650
|
+
this.gitManager.quietMode = true;
|
|
570
651
|
this.gitManager.validateGitHubCliInstallation();
|
|
571
|
-
const authType = this.configManager.getGithubAuthType();
|
|
572
|
-
if (authType === 'gh-cli') {
|
|
573
|
-
console.log(chalk.green('✅ GitHub CLI is installed'));
|
|
574
|
-
}
|
|
575
|
-
if (!this.gitManager) {
|
|
576
|
-
throw new Error('GitManager not initialized');
|
|
577
|
-
}
|
|
578
652
|
this.gitManager.validateGitHubCliAuthentication();
|
|
579
|
-
if (authType === 'gh-cli') {
|
|
580
|
-
console.log(chalk.green('✅ GitHub CLI is authenticated'));
|
|
581
|
-
}
|
|
582
|
-
else {
|
|
583
|
-
console.log(chalk.green('✅ GitHub PAT is configured'));
|
|
584
|
-
}
|
|
585
|
-
const repoInfo = this.repositoryManager.getRepositoryInfo(this.workingDir);
|
|
586
|
-
console.log(chalk.blue(`📂 Working in: ${repoInfo.name} (${repoInfo.branch})`));
|
|
587
|
-
console.log('');
|
|
588
653
|
// Get or create repository in database
|
|
589
654
|
const repository = await this.repositoryManager.getOrCreateRepository(this.workingDir);
|
|
590
655
|
// Load repository-specific instructions
|
|
591
656
|
this.repoInstructions = await this.configManager.getRepoInstructions(this.workingDir);
|
|
592
|
-
if (this.repoInstructions) {
|
|
593
|
-
console.log(chalk.green('✅ Repository-specific instructions loaded'));
|
|
594
|
-
}
|
|
595
657
|
// Process tasks based on config
|
|
596
658
|
let finalTasks = config.tasks;
|
|
597
659
|
const prStrategy = config.prStrategy || 'multiple';
|
|
598
660
|
// If single task and generateSubtasks is true, break it down
|
|
599
661
|
if (config.tasks.length === 1 && config.generateSubtasks) {
|
|
600
|
-
console.log(chalk.blue('🔍 Generating subtasks...'));
|
|
601
662
|
finalTasks = await this.jobManager.generateTaskBreakdownWithClaude(config.tasks[0], this.workingDir);
|
|
602
|
-
console.log(chalk.green(`✅ Generated ${finalTasks.length} subtasks`));
|
|
603
663
|
}
|
|
604
664
|
// Create job and tasks
|
|
605
665
|
const jobDescription = config.tasks.length === 1 ? config.tasks[0] : `Multiple tasks: ${config.tasks.slice(0, 2).join(', ')}${config.tasks.length > 2 ? '...' : ''}`;
|
|
@@ -612,20 +672,16 @@ export class TaskExecutor {
|
|
|
612
672
|
tasks.push(task);
|
|
613
673
|
}
|
|
614
674
|
}
|
|
615
|
-
console.log('');
|
|
616
|
-
console.log(chalk.blue.bold(`📋 Executing ${tasks.length} task(s)...`));
|
|
617
675
|
const shouldWaitForComments = config.waitForComments || false;
|
|
618
|
-
// Execute tasks based on PR strategy
|
|
676
|
+
// Execute tasks based on PR strategy (quiet mode)
|
|
619
677
|
if (prStrategy === 'single' && tasks.length > 1) {
|
|
620
|
-
await this.executeTasksWithSinglePR(tasks);
|
|
678
|
+
await this.executeTasksWithSinglePR(tasks, true);
|
|
621
679
|
}
|
|
622
680
|
else {
|
|
623
681
|
for (const task of tasks) {
|
|
624
|
-
await this.executeTask(task);
|
|
682
|
+
await this.executeTask(task, true);
|
|
625
683
|
}
|
|
626
684
|
}
|
|
627
|
-
console.log('');
|
|
628
|
-
console.log(chalk.green.bold('🎉 All initial tasks completed successfully!'));
|
|
629
685
|
// Collect PR URLs
|
|
630
686
|
const createdPRUrls = [];
|
|
631
687
|
for (const task of tasks) {
|
|
@@ -634,44 +690,20 @@ export class TaskExecutor {
|
|
|
634
690
|
createdPRUrls.push(updatedTask.pr_link);
|
|
635
691
|
}
|
|
636
692
|
}
|
|
693
|
+
// Output final results
|
|
637
694
|
if (createdPRUrls.length > 0) {
|
|
638
|
-
console.log(
|
|
639
|
-
console.log(chalk.blue('📋 PRs created:'));
|
|
640
|
-
createdPRUrls.forEach(url => console.log(chalk.cyan(` - ${url}`)));
|
|
695
|
+
createdPRUrls.forEach(url => console.log(url));
|
|
641
696
|
if (shouldWaitForComments) {
|
|
642
|
-
// Wait 30 minutes for reviewers to comment
|
|
643
|
-
console.log('');
|
|
644
|
-
console.log(chalk.blue('⏰ Waiting 30 minutes for PR reviews...'));
|
|
645
|
-
console.log(chalk.gray('PRs being monitored:'));
|
|
646
|
-
createdPRUrls.forEach(url => console.log(chalk.gray(` - ${url}`)));
|
|
647
|
-
console.log('');
|
|
697
|
+
// Wait 30 minutes for reviewers to comment (silent wait)
|
|
648
698
|
const waitTime = 30 * 60 * 1000; // 30 minutes in milliseconds
|
|
649
|
-
const startTime = Date.now();
|
|
650
|
-
const interval = setInterval(() => {
|
|
651
|
-
const elapsed = Date.now() - startTime;
|
|
652
|
-
const remaining = waitTime - elapsed;
|
|
653
|
-
const minutes = Math.floor(remaining / 60000);
|
|
654
|
-
const seconds = Math.floor((remaining % 60000) / 1000);
|
|
655
|
-
process.stdout.write(`\r${chalk.blue('⏰')} Time remaining: ${minutes}:${seconds.toString().padStart(2, '0')} `);
|
|
656
|
-
}, 1000);
|
|
657
699
|
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
658
|
-
clearInterval(interval);
|
|
659
|
-
console.log('\n');
|
|
660
700
|
// Check for unaddressed comments on created PRs
|
|
661
|
-
console.log(chalk.blue('🔍 Checking for PR review comments...'));
|
|
662
701
|
const prService = createPRService(this.workingDir);
|
|
663
702
|
const addressTasks = await this.checkAndCreateAddressTasks(createdPRUrls, prService);
|
|
664
703
|
if (addressTasks.length > 0) {
|
|
665
|
-
|
|
666
|
-
console.log(chalk.blue.bold(`📋 Found ${addressTasks.length} comments to address`));
|
|
667
|
-
// Execute address tasks automatically
|
|
704
|
+
// Execute address tasks automatically (quiet mode)
|
|
668
705
|
const addressExecutor = new AddressTaskExecutor();
|
|
669
|
-
await addressExecutor.executeAddressTasks(addressTasks);
|
|
670
|
-
console.log('');
|
|
671
|
-
console.log(chalk.green.bold('🎉 All PR comments addressed successfully!'));
|
|
672
|
-
}
|
|
673
|
-
else {
|
|
674
|
-
console.log(chalk.green('✨ No unaddressed comments found on PRs!'));
|
|
706
|
+
await addressExecutor.executeAddressTasks(addressTasks, true);
|
|
675
707
|
}
|
|
676
708
|
}
|
|
677
709
|
}
|