@link-assistant/hive-mind 0.46.0 ā 0.47.0
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/CHANGELOG.md +26 -13
- package/README.md +42 -8
- package/package.json +16 -3
- package/src/agent.lib.mjs +49 -70
- package/src/agent.prompts.lib.mjs +6 -20
- package/src/buildUserMention.lib.mjs +4 -17
- package/src/claude-limits.lib.mjs +15 -15
- package/src/claude.lib.mjs +617 -626
- package/src/claude.prompts.lib.mjs +7 -22
- package/src/codex.lib.mjs +39 -71
- package/src/codex.prompts.lib.mjs +6 -20
- package/src/config.lib.mjs +3 -16
- package/src/contributing-guidelines.lib.mjs +5 -18
- package/src/exit-handler.lib.mjs +4 -4
- package/src/git.lib.mjs +7 -7
- package/src/github-issue-creator.lib.mjs +17 -17
- package/src/github-linking.lib.mjs +8 -33
- package/src/github.batch.lib.mjs +20 -16
- package/src/github.graphql.lib.mjs +18 -18
- package/src/github.lib.mjs +89 -91
- package/src/hive.config.lib.mjs +50 -50
- package/src/hive.mjs +1293 -1296
- package/src/instrument.mjs +7 -11
- package/src/interactive-mode.lib.mjs +112 -138
- package/src/lenv-reader.lib.mjs +1 -6
- package/src/lib.mjs +36 -45
- package/src/lino.lib.mjs +2 -2
- package/src/local-ci-checks.lib.mjs +15 -14
- package/src/memory-check.mjs +52 -60
- package/src/model-mapping.lib.mjs +25 -32
- package/src/model-validation.lib.mjs +31 -31
- package/src/opencode.lib.mjs +37 -62
- package/src/opencode.prompts.lib.mjs +7 -21
- package/src/protect-branch.mjs +14 -15
- package/src/review.mjs +28 -27
- package/src/reviewers-hive.mjs +64 -69
- package/src/sentry.lib.mjs +13 -10
- package/src/solve.auto-continue.lib.mjs +48 -38
- package/src/solve.auto-pr.lib.mjs +111 -69
- package/src/solve.branch-errors.lib.mjs +17 -46
- package/src/solve.branch.lib.mjs +16 -23
- package/src/solve.config.lib.mjs +263 -261
- package/src/solve.error-handlers.lib.mjs +21 -79
- package/src/solve.execution.lib.mjs +10 -18
- package/src/solve.feedback.lib.mjs +25 -46
- package/src/solve.mjs +59 -60
- package/src/solve.preparation.lib.mjs +10 -36
- package/src/solve.repo-setup.lib.mjs +4 -19
- package/src/solve.repository.lib.mjs +37 -37
- package/src/solve.results.lib.mjs +32 -46
- package/src/solve.session.lib.mjs +7 -22
- package/src/solve.validation.lib.mjs +19 -17
- package/src/solve.watch.lib.mjs +20 -33
- package/src/start-screen.mjs +24 -24
- package/src/task.mjs +38 -44
- package/src/telegram-bot.mjs +125 -121
- package/src/telegram-top-command.lib.mjs +32 -48
- package/src/usage-limit.lib.mjs +9 -13
- package/src/version-info.lib.mjs +1 -1
- package/src/version.lib.mjs +1 -1
- package/src/youtrack/solve.youtrack.lib.mjs +3 -8
- package/src/youtrack/youtrack-sync.mjs +8 -14
- package/src/youtrack/youtrack.lib.mjs +26 -28
package/src/reviewers-hive.mjs
CHANGED
|
@@ -16,18 +16,18 @@ let logFile = null;
|
|
|
16
16
|
// Helper function to log to both console and file
|
|
17
17
|
const log = async (message, options = {}) => {
|
|
18
18
|
const { level = 'info', verbose = false } = options;
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
// Skip verbose logs unless --verbose is enabled
|
|
21
21
|
if (verbose && !global.verboseMode) {
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
// Write to file if log file is set
|
|
26
26
|
if (logFile) {
|
|
27
27
|
const logMessage = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}`;
|
|
28
28
|
await fs.appendFile(logFile, logMessage + '\n').catch(() => {});
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
|
|
31
31
|
// Write to console based on level
|
|
32
32
|
switch (level) {
|
|
33
33
|
case 'error':
|
|
@@ -49,92 +49,91 @@ const argv = yargs(process.argv.slice(2))
|
|
|
49
49
|
.usage('Usage: $0 <github-url> [options]')
|
|
50
50
|
.positional('github-url', {
|
|
51
51
|
type: 'string',
|
|
52
|
-
description: 'GitHub organization, repository, or user URL to monitor for pull requests'
|
|
52
|
+
description: 'GitHub organization, repository, or user URL to monitor for pull requests',
|
|
53
53
|
})
|
|
54
54
|
.option('review-label', {
|
|
55
55
|
type: 'string',
|
|
56
56
|
description: 'GitHub label to identify PRs needing review',
|
|
57
57
|
default: 'needs-review',
|
|
58
|
-
alias: 'l'
|
|
58
|
+
alias: 'l',
|
|
59
59
|
})
|
|
60
60
|
.option('all-prs', {
|
|
61
61
|
type: 'boolean',
|
|
62
62
|
description: 'Review all open pull requests regardless of labels',
|
|
63
63
|
default: false,
|
|
64
|
-
alias: 'a'
|
|
64
|
+
alias: 'a',
|
|
65
65
|
})
|
|
66
66
|
.option('skip-draft', {
|
|
67
67
|
type: 'boolean',
|
|
68
68
|
description: 'Skip draft pull requests',
|
|
69
69
|
default: true,
|
|
70
|
-
alias: 'd'
|
|
70
|
+
alias: 'd',
|
|
71
71
|
})
|
|
72
72
|
.option('skip-approved', {
|
|
73
73
|
type: 'boolean',
|
|
74
74
|
description: 'Skip pull requests that already have approvals',
|
|
75
|
-
default: true
|
|
75
|
+
default: true,
|
|
76
76
|
})
|
|
77
77
|
.option('concurrency', {
|
|
78
78
|
type: 'number',
|
|
79
79
|
description: 'Number of concurrent review.mjs instances',
|
|
80
80
|
default: 2,
|
|
81
|
-
alias: 'c'
|
|
81
|
+
alias: 'c',
|
|
82
82
|
})
|
|
83
83
|
.option('reviews-per-pr', {
|
|
84
84
|
type: 'number',
|
|
85
85
|
description: 'Number of reviews to generate per PR (for diverse perspectives)',
|
|
86
86
|
default: 1,
|
|
87
|
-
alias: 'r'
|
|
87
|
+
alias: 'r',
|
|
88
88
|
})
|
|
89
89
|
.option('model', {
|
|
90
90
|
type: 'string',
|
|
91
91
|
description: 'Model to use for review.mjs (opus or sonnet)',
|
|
92
92
|
alias: 'm',
|
|
93
93
|
default: 'opus',
|
|
94
|
-
choices: ['opus', 'sonnet']
|
|
94
|
+
choices: ['opus', 'sonnet'],
|
|
95
95
|
})
|
|
96
96
|
.option('focus', {
|
|
97
97
|
type: 'string',
|
|
98
98
|
description: 'Focus areas for reviews (security, performance, logic, style, tests, all)',
|
|
99
99
|
default: 'all',
|
|
100
|
-
alias: 'f'
|
|
100
|
+
alias: 'f',
|
|
101
101
|
})
|
|
102
102
|
.option('auto-approve', {
|
|
103
103
|
type: 'boolean',
|
|
104
104
|
description: 'Auto-approve PRs that pass review criteria',
|
|
105
|
-
default: false
|
|
105
|
+
default: false,
|
|
106
106
|
})
|
|
107
107
|
.option('interval', {
|
|
108
108
|
type: 'number',
|
|
109
109
|
description: 'Polling interval in seconds',
|
|
110
110
|
default: 300, // 5 minutes
|
|
111
|
-
alias: 'i'
|
|
111
|
+
alias: 'i',
|
|
112
112
|
})
|
|
113
113
|
.option('max-prs', {
|
|
114
114
|
type: 'number',
|
|
115
115
|
description: 'Maximum number of PRs to process (0 = unlimited)',
|
|
116
|
-
default: 0
|
|
116
|
+
default: 0,
|
|
117
117
|
})
|
|
118
118
|
.option('dry-run', {
|
|
119
119
|
type: 'boolean',
|
|
120
120
|
description: 'List PRs that would be reviewed without actually reviewing them',
|
|
121
|
-
default: false
|
|
121
|
+
default: false,
|
|
122
122
|
})
|
|
123
123
|
.option('verbose', {
|
|
124
124
|
type: 'boolean',
|
|
125
125
|
description: 'Enable verbose logging',
|
|
126
126
|
alias: 'v',
|
|
127
|
-
default: false
|
|
127
|
+
default: false,
|
|
128
128
|
})
|
|
129
129
|
.option('once', {
|
|
130
130
|
type: 'boolean',
|
|
131
131
|
description: 'Run once and exit instead of continuous monitoring',
|
|
132
|
-
default: false
|
|
132
|
+
default: false,
|
|
133
133
|
})
|
|
134
134
|
.demandCommand(1, 'GitHub URL is required')
|
|
135
135
|
.help('h')
|
|
136
|
-
.alias('h', 'help')
|
|
137
|
-
.argv;
|
|
136
|
+
.alias('h', 'help').argv;
|
|
138
137
|
|
|
139
138
|
const githubUrl = argv['github-url'] || argv._[0];
|
|
140
139
|
|
|
@@ -227,9 +226,7 @@ class PRQueue {
|
|
|
227
226
|
|
|
228
227
|
// Add PR to queue if not already processed or in queue
|
|
229
228
|
enqueue(prUrl) {
|
|
230
|
-
if (this.completed.has(prUrl) ||
|
|
231
|
-
this.processing.has(prUrl) ||
|
|
232
|
-
this.queue.includes(prUrl)) {
|
|
229
|
+
if (this.completed.has(prUrl) || this.processing.has(prUrl) || this.queue.includes(prUrl)) {
|
|
233
230
|
return false;
|
|
234
231
|
}
|
|
235
232
|
this.queue.push(prUrl);
|
|
@@ -264,7 +261,7 @@ class PRQueue {
|
|
|
264
261
|
queued: this.queue.length,
|
|
265
262
|
processing: this.processing.size,
|
|
266
263
|
completed: this.completed.size,
|
|
267
|
-
failed: this.failed.size
|
|
264
|
+
failed: this.failed.size,
|
|
268
265
|
};
|
|
269
266
|
}
|
|
270
267
|
|
|
@@ -280,10 +277,10 @@ const prQueue = new PRQueue();
|
|
|
280
277
|
// Worker function to review PRs from queue
|
|
281
278
|
async function reviewer(reviewerId) {
|
|
282
279
|
await log(`š Reviewer ${reviewerId} started`, { verbose: true });
|
|
283
|
-
|
|
280
|
+
|
|
284
281
|
while (prQueue.isRunning) {
|
|
285
282
|
const prUrl = prQueue.dequeue();
|
|
286
|
-
|
|
283
|
+
|
|
287
284
|
if (!prUrl) {
|
|
288
285
|
// No work available, wait a bit
|
|
289
286
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
@@ -291,13 +288,13 @@ async function reviewer(reviewerId) {
|
|
|
291
288
|
}
|
|
292
289
|
|
|
293
290
|
await log(`\nš Reviewer ${reviewerId} reviewing: ${prUrl}`);
|
|
294
|
-
|
|
291
|
+
|
|
295
292
|
// Review the PR multiple times if needed (for diverse perspectives)
|
|
296
293
|
for (let reviewNum = 1; reviewNum <= argv.reviewsPerPr; reviewNum++) {
|
|
297
294
|
if (argv.reviewsPerPr > 1) {
|
|
298
295
|
await log(` š Creating review ${reviewNum}/${argv.reviewsPerPr} for PR`);
|
|
299
296
|
}
|
|
300
|
-
|
|
297
|
+
|
|
301
298
|
try {
|
|
302
299
|
if (argv.dryRun) {
|
|
303
300
|
await log(` š§Ŗ [DRY RUN] Would execute: ./review.mjs "${prUrl}" --model ${argv.model} --focus ${argv.focus}${argv.autoApprove ? ' --approve' : ''}`);
|
|
@@ -305,14 +302,14 @@ async function reviewer(reviewerId) {
|
|
|
305
302
|
} else {
|
|
306
303
|
// Execute review.mjs using command-stream
|
|
307
304
|
await log(` š Executing review.mjs for ${prUrl}...`);
|
|
308
|
-
|
|
305
|
+
|
|
309
306
|
const startTime = Date.now();
|
|
310
307
|
let reviewCommand = $`./review.mjs "${prUrl}" --model ${argv.model} --focus ${argv.focus}`;
|
|
311
|
-
|
|
308
|
+
|
|
312
309
|
if (argv.autoApprove) {
|
|
313
310
|
reviewCommand = $`./review.mjs "${prUrl}" --model ${argv.model} --focus ${argv.focus} --approve`;
|
|
314
311
|
}
|
|
315
|
-
|
|
312
|
+
|
|
316
313
|
// Stream output and capture result
|
|
317
314
|
let exitCode = 0;
|
|
318
315
|
for await (const chunk of reviewCommand.stream()) {
|
|
@@ -330,16 +327,16 @@ async function reviewer(reviewerId) {
|
|
|
330
327
|
exitCode = chunk.code;
|
|
331
328
|
}
|
|
332
329
|
}
|
|
333
|
-
|
|
330
|
+
|
|
334
331
|
const duration = Math.round((Date.now() - startTime) / 1000);
|
|
335
|
-
|
|
332
|
+
|
|
336
333
|
if (exitCode === 0) {
|
|
337
334
|
await log(` ā
Reviewer ${reviewerId} completed ${prUrl} (${duration}s)`);
|
|
338
335
|
} else {
|
|
339
336
|
throw new Error(`review.mjs exited with code ${exitCode}`);
|
|
340
337
|
}
|
|
341
338
|
}
|
|
342
|
-
|
|
339
|
+
|
|
343
340
|
// Small delay between multiple reviews for same PR
|
|
344
341
|
if (reviewNum < argv.reviewsPerPr) {
|
|
345
342
|
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
@@ -350,14 +347,14 @@ async function reviewer(reviewerId) {
|
|
|
350
347
|
break; // Stop trying more reviews for this PR
|
|
351
348
|
}
|
|
352
349
|
}
|
|
353
|
-
|
|
350
|
+
|
|
354
351
|
prQueue.markCompleted(prUrl);
|
|
355
|
-
|
|
352
|
+
|
|
356
353
|
// Show queue stats
|
|
357
354
|
const stats = prQueue.getStats();
|
|
358
355
|
await log(` š Queue: ${stats.queued} waiting, ${stats.processing} reviewing, ${stats.completed} completed, ${stats.failed} failed`);
|
|
359
356
|
}
|
|
360
|
-
|
|
357
|
+
|
|
361
358
|
await log(`š Reviewer ${reviewerId} stopped`, { verbose: true });
|
|
362
359
|
}
|
|
363
360
|
|
|
@@ -379,12 +376,12 @@ async function hasApprovals(prUrl) {
|
|
|
379
376
|
|
|
380
377
|
const { stdout } = await execAsync(cmd, { encoding: 'utf8', env: process.env });
|
|
381
378
|
const approvalCount = parseInt(stdout.trim()) || 0;
|
|
382
|
-
|
|
379
|
+
|
|
383
380
|
if (approvalCount > 0) {
|
|
384
381
|
await log(` ā³ Skipping (has ${approvalCount} approval${approvalCount > 1 ? 's' : ''})`, { verbose: true });
|
|
385
382
|
return true;
|
|
386
383
|
}
|
|
387
|
-
|
|
384
|
+
|
|
388
385
|
return false;
|
|
389
386
|
} catch (error) {
|
|
390
387
|
// If we can't check, assume no approvals
|
|
@@ -400,10 +397,10 @@ async function fetchPullRequests() {
|
|
|
400
397
|
} else {
|
|
401
398
|
await log(`\nš Fetching pull requests with label "${argv.reviewLabel}"...`);
|
|
402
399
|
}
|
|
403
|
-
|
|
400
|
+
|
|
404
401
|
try {
|
|
405
402
|
let prs = [];
|
|
406
|
-
|
|
403
|
+
|
|
407
404
|
if (argv.allPrs) {
|
|
408
405
|
// Fetch all open PRs without label filter
|
|
409
406
|
let searchCmd;
|
|
@@ -415,7 +412,7 @@ async function fetchPullRequests() {
|
|
|
415
412
|
// User scope
|
|
416
413
|
searchCmd = `gh search prs user:${owner} is:open --limit 100 --json url,title,number,repository,isDraft`;
|
|
417
414
|
}
|
|
418
|
-
|
|
415
|
+
|
|
419
416
|
await log(` š Command: ${searchCmd}`, { verbose: true });
|
|
420
417
|
|
|
421
418
|
// Use async exec to avoid escaping issues
|
|
@@ -424,7 +421,6 @@ async function fetchPullRequests() {
|
|
|
424
421
|
const execAsync = promisify(exec);
|
|
425
422
|
const { stdout } = await execAsync(searchCmd, { encoding: 'utf8', env: process.env });
|
|
426
423
|
prs = JSON.parse(stdout || '[]');
|
|
427
|
-
|
|
428
424
|
} else {
|
|
429
425
|
// Use label filter
|
|
430
426
|
const { exec } = await import('child_process');
|
|
@@ -451,11 +447,11 @@ async function fetchPullRequests() {
|
|
|
451
447
|
} else {
|
|
452
448
|
baseQuery = `user:${owner} is:pr is:open`;
|
|
453
449
|
}
|
|
454
|
-
|
|
450
|
+
|
|
455
451
|
// Handle label with potential spaces
|
|
456
452
|
let searchQuery;
|
|
457
453
|
let searchCmd;
|
|
458
|
-
|
|
454
|
+
|
|
459
455
|
if (argv.reviewLabel.includes(' ')) {
|
|
460
456
|
searchQuery = `${baseQuery} label:"${argv.reviewLabel}"`;
|
|
461
457
|
searchCmd = `gh search prs '${searchQuery}' --limit 100 --json url,title,number,repository,isDraft`;
|
|
@@ -463,7 +459,7 @@ async function fetchPullRequests() {
|
|
|
463
459
|
searchQuery = `${baseQuery} label:${argv.reviewLabel}`;
|
|
464
460
|
searchCmd = `gh search prs '${searchQuery}' --limit 100 --json url,title,number,repository,isDraft`;
|
|
465
461
|
}
|
|
466
|
-
|
|
462
|
+
|
|
467
463
|
await log(` š Search query: ${searchQuery}`, { verbose: true });
|
|
468
464
|
await log(` š Command: ${searchCmd}`, { verbose: true });
|
|
469
465
|
|
|
@@ -476,7 +472,7 @@ async function fetchPullRequests() {
|
|
|
476
472
|
}
|
|
477
473
|
}
|
|
478
474
|
}
|
|
479
|
-
|
|
475
|
+
|
|
480
476
|
if (prs.length === 0) {
|
|
481
477
|
if (argv.allPrs) {
|
|
482
478
|
await log(' ā¹ļø No open pull requests found');
|
|
@@ -485,13 +481,13 @@ async function fetchPullRequests() {
|
|
|
485
481
|
}
|
|
486
482
|
return [];
|
|
487
483
|
}
|
|
488
|
-
|
|
484
|
+
|
|
489
485
|
if (argv.allPrs) {
|
|
490
486
|
await log(` š Found ${prs.length} open pull request(s)`);
|
|
491
487
|
} else {
|
|
492
488
|
await log(` š Found ${prs.length} pull request(s) with label "${argv.reviewLabel}"`);
|
|
493
489
|
}
|
|
494
|
-
|
|
490
|
+
|
|
495
491
|
// Filter out draft PRs if option is enabled
|
|
496
492
|
if (argv.skipDraft) {
|
|
497
493
|
const nonDraftPrs = prs.filter(pr => !pr.isDraft);
|
|
@@ -501,19 +497,19 @@ async function fetchPullRequests() {
|
|
|
501
497
|
}
|
|
502
498
|
prs = nonDraftPrs;
|
|
503
499
|
}
|
|
504
|
-
|
|
500
|
+
|
|
505
501
|
// Apply max PRs limit if set
|
|
506
502
|
let prsToProcess = prs;
|
|
507
503
|
if (argv.maxPrs > 0 && prs.length > argv.maxPrs) {
|
|
508
504
|
prsToProcess = prs.slice(0, argv.maxPrs);
|
|
509
505
|
await log(` š¢ Limiting to first ${argv.maxPrs} PRs`);
|
|
510
506
|
}
|
|
511
|
-
|
|
507
|
+
|
|
512
508
|
// Filter out PRs with approvals if option is enabled
|
|
513
509
|
if (argv.skipApproved) {
|
|
514
510
|
await log(' š Checking for existing approvals...');
|
|
515
511
|
const filteredPrs = [];
|
|
516
|
-
|
|
512
|
+
|
|
517
513
|
for (const pr of prsToProcess) {
|
|
518
514
|
const hasApproval = await hasApprovals(pr.url);
|
|
519
515
|
if (hasApproval) {
|
|
@@ -522,14 +518,14 @@ async function fetchPullRequests() {
|
|
|
522
518
|
filteredPrs.push(pr);
|
|
523
519
|
}
|
|
524
520
|
}
|
|
525
|
-
|
|
521
|
+
|
|
526
522
|
const skippedCount = prsToProcess.length - filteredPrs.length;
|
|
527
523
|
if (skippedCount > 0) {
|
|
528
524
|
await log(` āļø Skipped ${skippedCount} PR(s) with existing approvals`);
|
|
529
525
|
}
|
|
530
526
|
prsToProcess = filteredPrs;
|
|
531
527
|
}
|
|
532
|
-
|
|
528
|
+
|
|
533
529
|
// In dry-run mode, show the PRs that would be reviewed
|
|
534
530
|
if (argv.dryRun && prsToProcess.length > 0) {
|
|
535
531
|
await log('\n š PRs that would be reviewed:');
|
|
@@ -537,9 +533,8 @@ async function fetchPullRequests() {
|
|
|
537
533
|
await log(` - ${pr.title || 'Untitled'} (${pr.url})`);
|
|
538
534
|
}
|
|
539
535
|
}
|
|
540
|
-
|
|
536
|
+
|
|
541
537
|
return prsToProcess.map(pr => pr.url);
|
|
542
|
-
|
|
543
538
|
} catch (error) {
|
|
544
539
|
await log(` ā Error fetching pull requests: ${error.message}`, { level: 'error' });
|
|
545
540
|
return [];
|
|
@@ -549,22 +544,22 @@ async function fetchPullRequests() {
|
|
|
549
544
|
// Main monitoring loop
|
|
550
545
|
async function monitor() {
|
|
551
546
|
await log('\nš Starting Reviewers Hive Mind monitoring system...');
|
|
552
|
-
|
|
547
|
+
|
|
553
548
|
// Start reviewers
|
|
554
549
|
await log(`\nš Starting ${argv.concurrency} reviewers...`);
|
|
555
550
|
for (let i = 1; i <= argv.concurrency; i++) {
|
|
556
551
|
prQueue.workers.push(reviewer(i));
|
|
557
552
|
}
|
|
558
|
-
|
|
553
|
+
|
|
559
554
|
// Main monitoring loop
|
|
560
555
|
let iteration = 0;
|
|
561
556
|
while (true) {
|
|
562
557
|
iteration++;
|
|
563
558
|
await log(`\nš Monitoring iteration ${iteration} at ${new Date().toISOString()}`);
|
|
564
|
-
|
|
559
|
+
|
|
565
560
|
// Fetch PRs
|
|
566
561
|
const prUrls = await fetchPullRequests();
|
|
567
|
-
|
|
562
|
+
|
|
568
563
|
// Add new PRs to queue
|
|
569
564
|
let newPrs = 0;
|
|
570
565
|
for (const url of prUrls) {
|
|
@@ -573,13 +568,13 @@ async function monitor() {
|
|
|
573
568
|
await log(` ā Added to review queue: ${url}`);
|
|
574
569
|
}
|
|
575
570
|
}
|
|
576
|
-
|
|
571
|
+
|
|
577
572
|
if (newPrs > 0) {
|
|
578
573
|
await log(` š„ Added ${newPrs} new PR(s) to review queue`);
|
|
579
574
|
} else {
|
|
580
575
|
await log(' ā¹ļø No new PRs to add (all already reviewed or in queue)');
|
|
581
576
|
}
|
|
582
|
-
|
|
577
|
+
|
|
583
578
|
// Show current stats
|
|
584
579
|
const stats = prQueue.getStats();
|
|
585
580
|
await log('\nš Current Status:');
|
|
@@ -587,11 +582,11 @@ async function monitor() {
|
|
|
587
582
|
await log(` āļø Reviewing: ${stats.processing}`);
|
|
588
583
|
await log(` ā
Completed: ${stats.completed}`);
|
|
589
584
|
await log(` ā Failed: ${stats.failed}`);
|
|
590
|
-
|
|
585
|
+
|
|
591
586
|
// If running once, wait for queue to empty then exit
|
|
592
587
|
if (argv.once) {
|
|
593
588
|
await log('\nš Single run mode - waiting for review queue to empty...');
|
|
594
|
-
|
|
589
|
+
|
|
595
590
|
while (stats.queued > 0 || stats.processing > 0) {
|
|
596
591
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
597
592
|
const currentStats = prQueue.getStats();
|
|
@@ -600,22 +595,22 @@ async function monitor() {
|
|
|
600
595
|
}
|
|
601
596
|
Object.assign(stats, currentStats);
|
|
602
597
|
}
|
|
603
|
-
|
|
598
|
+
|
|
604
599
|
await log('\nā
All PRs reviewed!');
|
|
605
600
|
await log(` Completed: ${stats.completed}`);
|
|
606
601
|
await log(` Failed: ${stats.failed}`);
|
|
607
602
|
break;
|
|
608
603
|
}
|
|
609
|
-
|
|
604
|
+
|
|
610
605
|
// Wait for next iteration
|
|
611
606
|
await log(`\nā° Next check in ${argv.interval} seconds...`);
|
|
612
607
|
await new Promise(resolve => setTimeout(resolve, argv.interval * 1000));
|
|
613
608
|
}
|
|
614
|
-
|
|
609
|
+
|
|
615
610
|
// Stop reviewers
|
|
616
611
|
prQueue.stop();
|
|
617
612
|
await Promise.all(prQueue.workers);
|
|
618
|
-
|
|
613
|
+
|
|
619
614
|
await log('\nš Reviewers Hive Mind monitoring stopped');
|
|
620
615
|
}
|
|
621
616
|
|
|
@@ -640,4 +635,4 @@ try {
|
|
|
640
635
|
} catch (error) {
|
|
641
636
|
await log(`\nā Fatal error: ${error.message}`, { level: 'error' });
|
|
642
637
|
process.exit(1);
|
|
643
|
-
}
|
|
638
|
+
}
|
package/src/sentry.lib.mjs
CHANGED
|
@@ -117,12 +117,15 @@ export const withSpan = async (name, callback) => {
|
|
|
117
117
|
return callback();
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
return sentry.startSpan(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
120
|
+
return sentry.startSpan(
|
|
121
|
+
{
|
|
122
|
+
name,
|
|
123
|
+
op: 'function',
|
|
124
|
+
},
|
|
125
|
+
async () => {
|
|
126
|
+
return callback();
|
|
127
|
+
}
|
|
128
|
+
);
|
|
126
129
|
};
|
|
127
130
|
|
|
128
131
|
/**
|
|
@@ -173,7 +176,7 @@ export const reportWarning = (warning, context = {}) => {
|
|
|
173
176
|
* Add breadcrumb for better error context
|
|
174
177
|
* @param {Object} breadcrumb - Breadcrumb data
|
|
175
178
|
*/
|
|
176
|
-
export const addBreadcrumb = async
|
|
179
|
+
export const addBreadcrumb = async breadcrumb => {
|
|
177
180
|
if (!isSentryEnabled() || sentryDisabled) {
|
|
178
181
|
return;
|
|
179
182
|
}
|
|
@@ -188,7 +191,7 @@ export const addBreadcrumb = async (breadcrumb) => {
|
|
|
188
191
|
* Set user context for Sentry
|
|
189
192
|
* @param {Object} user - User data
|
|
190
193
|
*/
|
|
191
|
-
export const setUserContext = async
|
|
194
|
+
export const setUserContext = async user => {
|
|
192
195
|
if (!isSentryEnabled() || sentryDisabled) {
|
|
193
196
|
return;
|
|
194
197
|
}
|
|
@@ -219,7 +222,7 @@ export const setExtraContext = async (key, value) => {
|
|
|
219
222
|
* Set tags for Sentry
|
|
220
223
|
* @param {Object} tags - Tags to set
|
|
221
224
|
*/
|
|
222
|
-
export const setTags = async
|
|
225
|
+
export const setTags = async tags => {
|
|
223
226
|
if (!isSentryEnabled() || sentryDisabled) {
|
|
224
227
|
return;
|
|
225
228
|
}
|
|
@@ -281,4 +284,4 @@ export const closeSentry = async (timeout = 2000) => {
|
|
|
281
284
|
};
|
|
282
285
|
|
|
283
286
|
// Export the Sentry check function
|
|
284
|
-
export { isSentryEnabled };
|
|
287
|
+
export { isSentryEnabled };
|