@link-assistant/hive-mind 1.78.1 → 1.78.2
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 +6 -0
- package/package.json +1 -1
- package/src/session-monitor.lib.mjs +82 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.78.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 70db26f: Ensure Telegram work-session completion messages recover pull request links from completed solve logs when linked-issue lookup does not return a PR.
|
|
8
|
+
|
|
3
9
|
## 1.78.1
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* @see https://github.com/link-assistant/hive-mind/issues/380
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { promisify } from 'util';
|
|
19
18
|
import { exec as execCallback } from 'child_process';
|
|
19
|
+
import fs from 'fs/promises';
|
|
20
|
+
import { promisify } from 'util';
|
|
20
21
|
import { formatSessionCompletionMessage, getSessionCompletionExitCode } from './work-session-formatting.lib.mjs';
|
|
21
22
|
import { notifySubscribers, getSubscriberCount } from './telegram-subscribers.lib.mjs';
|
|
22
23
|
|
|
@@ -157,6 +158,45 @@ function normalizeSessionUrl(url) {
|
|
|
157
158
|
return url.replace(/#.*$/, '').replace(/\/+$/, '').toLowerCase();
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
const GITHUB_PULL_REQUEST_URL_RE = /https:\/\/github\.com\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)\/pull\/([0-9]+)/g;
|
|
162
|
+
|
|
163
|
+
export function extractPullRequestUrlFromText(text, { owner = null, repo = null } = {}) {
|
|
164
|
+
if (!text) return null;
|
|
165
|
+
|
|
166
|
+
const expectedOwner = owner ? String(owner).toLowerCase() : null;
|
|
167
|
+
const expectedRepo = repo ? String(repo).toLowerCase() : null;
|
|
168
|
+
const value = String(text);
|
|
169
|
+
GITHUB_PULL_REQUEST_URL_RE.lastIndex = 0;
|
|
170
|
+
|
|
171
|
+
let match;
|
|
172
|
+
while ((match = GITHUB_PULL_REQUEST_URL_RE.exec(value)) !== null) {
|
|
173
|
+
const [, matchOwner, matchRepo, pullNumber] = match;
|
|
174
|
+
if (expectedOwner && matchOwner.toLowerCase() !== expectedOwner) continue;
|
|
175
|
+
if (expectedRepo && matchRepo.toLowerCase() !== expectedRepo) continue;
|
|
176
|
+
return `https://github.com/${matchOwner}/${matchRepo}/pull/${pullNumber}`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function resolvePullRequestUrlFromSessionLog(logPath, ctx, { verbose = false, readFile = fs.readFile } = {}) {
|
|
183
|
+
if (!logPath) return null;
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const logText = await readFile(logPath, 'utf8');
|
|
187
|
+
const pullRequestUrl = extractPullRequestUrlFromText(logText, { owner: ctx.owner, repo: ctx.repo });
|
|
188
|
+
if (pullRequestUrl && verbose) {
|
|
189
|
+
console.log(`[VERBOSE] Found PR ${pullRequestUrl} in completed session log ${logPath}`);
|
|
190
|
+
}
|
|
191
|
+
return pullRequestUrl;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
if (verbose) {
|
|
194
|
+
console.log(`[VERBOSE] Could not inspect session log ${logPath} for PR URL: ${error?.message || error}`);
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
160
200
|
function isNonIsolationSessionActive(sessionName, sessionInfo, verbose = false) {
|
|
161
201
|
const startTime = sessionInfo.startTime instanceof Date ? sessionInfo.startTime : new Date(sessionInfo.startTime);
|
|
162
202
|
const elapsed = Date.now() - startTime.getTime();
|
|
@@ -272,13 +312,19 @@ export async function monitorSessions(bot, verbose = false, options = {}) {
|
|
|
272
312
|
try {
|
|
273
313
|
const finalExitCode = getSessionCompletionExitCode({ exitCode, statusResult });
|
|
274
314
|
|
|
275
|
-
// Issue #1688: When the original /solve URL was an issue, look up
|
|
276
|
-
//
|
|
277
|
-
// a `Pull request:` line.
|
|
278
|
-
//
|
|
315
|
+
// Issue #1688/#1905: When the original /solve URL was an issue, look up
|
|
316
|
+
// the created PR so the completion message can include both an
|
|
317
|
+
// `Issue:` and a `Pull request:` line. The linked-issue API can lag
|
|
318
|
+
// behind the solver's own verification log, so we also inspect the
|
|
319
|
+
// completed session log before giving up.
|
|
279
320
|
let pullRequestUrl = null;
|
|
280
321
|
try {
|
|
281
|
-
pullRequestUrl = await resolvePullRequestUrlForSession(sessionInfo, {
|
|
322
|
+
pullRequestUrl = await resolvePullRequestUrlForSession(sessionInfo, {
|
|
323
|
+
verbose,
|
|
324
|
+
lookupLinkedPullRequest: options.lookupLinkedPullRequest,
|
|
325
|
+
statusResult,
|
|
326
|
+
readFile: options.readFile,
|
|
327
|
+
});
|
|
282
328
|
} catch (lookupError) {
|
|
283
329
|
if (verbose) {
|
|
284
330
|
console.log(`[VERBOSE] Pull request lookup failed for ${sessionName}: ${lookupError?.message || lookupError}`);
|
|
@@ -395,36 +441,50 @@ export async function monitorSessions(bot, verbose = false, options = {}) {
|
|
|
395
441
|
* @param {Object} [options]
|
|
396
442
|
* @param {boolean} [options.verbose]
|
|
397
443
|
* @param {Function} [options.lookupLinkedPullRequest] - Optional override `(ctx) => Promise<string|null>`
|
|
444
|
+
* @param {Object} [options.statusResult] - Completed start-command status payload, including logPath
|
|
445
|
+
* @param {Function} [options.readFile] - Optional test override for reading session logs
|
|
398
446
|
* @returns {Promise<string|null>} PR URL or null
|
|
399
447
|
*
|
|
400
448
|
* @see https://github.com/link-assistant/hive-mind/issues/1688
|
|
449
|
+
* @see https://github.com/link-assistant/hive-mind/issues/1905
|
|
401
450
|
*/
|
|
402
|
-
async function resolvePullRequestUrlForSession(sessionInfo, { verbose = false, lookupLinkedPullRequest = null } = {}) {
|
|
451
|
+
async function resolvePullRequestUrlForSession(sessionInfo, { verbose = false, lookupLinkedPullRequest = null, statusResult = null, readFile = fs.readFile } = {}) {
|
|
403
452
|
const ctx = sessionInfo?.urlContext;
|
|
404
453
|
if (!ctx || ctx.type !== 'issue' || !ctx.owner || !ctx.repo || !ctx.number) {
|
|
405
454
|
return null;
|
|
406
455
|
}
|
|
407
456
|
|
|
408
457
|
if (typeof lookupLinkedPullRequest === 'function') {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
458
|
+
const linkedPullRequestUrl = await lookupLinkedPullRequest(ctx);
|
|
459
|
+
if (linkedPullRequestUrl) return linkedPullRequestUrl;
|
|
460
|
+
} else {
|
|
461
|
+
try {
|
|
462
|
+
const { batchCheckPullRequestsForIssues } = await import('./github.lib.mjs');
|
|
463
|
+
const result = await batchCheckPullRequestsForIssues(ctx.owner, ctx.repo, [ctx.number]);
|
|
464
|
+
const linkedPRs = result?.[ctx.number]?.linkedPRs || [];
|
|
465
|
+
if (linkedPRs.length > 0 && linkedPRs[0].url) {
|
|
466
|
+
if (verbose) {
|
|
467
|
+
console.log(`[VERBOSE] Found linked PR ${linkedPRs[0].url} for issue ${ctx.owner}/${ctx.repo}#${ctx.number}`);
|
|
468
|
+
}
|
|
469
|
+
return linkedPRs[0].url;
|
|
470
|
+
}
|
|
471
|
+
} catch (error) {
|
|
417
472
|
if (verbose) {
|
|
418
|
-
console.log(`[VERBOSE]
|
|
473
|
+
console.log(`[VERBOSE] batchCheckPullRequestsForIssues failed for ${ctx.owner}/${ctx.repo}#${ctx.number}: ${error?.message || error}`);
|
|
419
474
|
}
|
|
420
|
-
return linkedPRs[0].url;
|
|
421
|
-
}
|
|
422
|
-
} catch (error) {
|
|
423
|
-
if (verbose) {
|
|
424
|
-
console.log(`[VERBOSE] batchCheckPullRequestsForIssues failed for ${ctx.owner}/${ctx.repo}#${ctx.number}: ${error?.message || error}`);
|
|
425
475
|
}
|
|
426
|
-
throw error;
|
|
427
476
|
}
|
|
477
|
+
|
|
478
|
+
const logPath = statusResult?.logPath || sessionInfo?.logPath || null;
|
|
479
|
+
const pullRequestUrlFromLog = await resolvePullRequestUrlFromSessionLog(logPath, ctx, { verbose, readFile });
|
|
480
|
+
if (pullRequestUrlFromLog) return pullRequestUrlFromLog;
|
|
481
|
+
|
|
482
|
+
if (verbose && logPath) {
|
|
483
|
+
console.log(`[VERBOSE] No PR URL found for issue ${ctx.owner}/${ctx.repo}#${ctx.number} in session log ${logPath}`);
|
|
484
|
+
} else if (verbose) {
|
|
485
|
+
console.log(`[VERBOSE] No session log path available for PR URL fallback for issue ${ctx.owner}/${ctx.repo}#${ctx.number}`);
|
|
486
|
+
}
|
|
487
|
+
|
|
428
488
|
return null;
|
|
429
489
|
}
|
|
430
490
|
|