@link-assistant/hive-mind 1.59.5 → 1.59.7

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 (43) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/package.json +1 -1
  3. package/src/bidirectional-interactive.lib.mjs +1 -0
  4. package/src/contributing-guidelines.lib.mjs +3 -2
  5. package/src/github-error-reporter.lib.mjs +3 -2
  6. package/src/github-merge-ci-signals.lib.mjs +8 -2
  7. package/src/github-merge-ci.lib.mjs +8 -2
  8. package/src/github-merge-ready-sync.lib.mjs +7 -1
  9. package/src/github-merge-repo-actions.lib.mjs +7 -1
  10. package/src/github-merge.lib.mjs +40 -32
  11. package/src/github-rate-limit.lib.mjs +276 -0
  12. package/src/github.batch.lib.mjs +1 -0
  13. package/src/hive.mjs +2 -2
  14. package/src/hive.recheck.lib.mjs +1 -0
  15. package/src/lib.mjs +30 -4
  16. package/src/limits.lib.mjs +1 -0
  17. package/src/protect-branch.mjs +3 -2
  18. package/src/queue-config.lib.mjs +7 -3
  19. package/src/review.mjs +3 -2
  20. package/src/reviewers-hive.mjs +3 -2
  21. package/src/solve.accept-invite.lib.mjs +7 -1
  22. package/src/solve.auto-continue.lib.mjs +3 -2
  23. package/src/solve.auto-ensure.lib.mjs +3 -2
  24. package/src/solve.auto-merge-helpers.lib.mjs +3 -2
  25. package/src/solve.auto-merge.lib.mjs +40 -2
  26. package/src/solve.auto-pr.lib.mjs +1 -0
  27. package/src/solve.branch-errors.lib.mjs +1 -0
  28. package/src/solve.config.lib.mjs +2 -2
  29. package/src/solve.error-handlers.lib.mjs +1 -0
  30. package/src/solve.execution.lib.mjs +3 -2
  31. package/src/solve.feedback.lib.mjs +1 -0
  32. package/src/solve.mjs +20 -36
  33. package/src/solve.preparation.lib.mjs +1 -0
  34. package/src/solve.progress-monitoring.lib.mjs +1 -0
  35. package/src/solve.repository.lib.mjs +3 -3
  36. package/src/solve.restart-shared.lib.mjs +3 -2
  37. package/src/solve.results.lib.mjs +89 -14
  38. package/src/solve.session.lib.mjs +1 -0
  39. package/src/solve.watch.lib.mjs +39 -2
  40. package/src/telegram-accept-invitations.lib.mjs +7 -1
  41. package/src/token-sanitization.lib.mjs +1 -0
  42. package/src/tool-comments.lib.mjs +12 -1
  43. package/src/youtrack/youtrack-sync.mjs +1 -0
@@ -12,8 +12,9 @@ if (typeof globalThis.use === 'undefined') {
12
12
  const use = globalThis.use;
13
13
 
14
14
  // Use command-stream for consistent $ behavior across runtimes
15
- const { $ } = await use('command-stream');
16
-
15
+ const { $: __rawDollar$ } = await use('command-stream');
16
+ const { wrapDollarWithGhRetry } = await import('./github-rate-limit.lib.mjs');
17
+ const $ = wrapDollarWithGhRetry(__rawDollar$);
17
18
  const path = (await use('path')).default;
18
19
 
19
20
  // Import shared library functions
@@ -1178,11 +1179,17 @@ export const checkForAiCreatedComments = async (sessionStartTime, owner, repo, p
1178
1179
  };
1179
1180
 
1180
1181
  /**
1181
- * Attach the AI's solution summary as a comment to the PR or issue.
1182
+ * Attach the AI's working session summary as a comment to the PR or issue.
1182
1183
  * The summary is extracted from the tool's result field and posted
1183
- * with a "Solution summary" header.
1184
+ * with a "Working session summary" header.
1184
1185
  *
1185
1186
  * Issue #1263: Support for --attach-solution-summary and --auto-attach-solution-summary
1187
+ * Issue #1728: Renamed comment header from "Solution summary" to "Working session
1188
+ * summary" so it accurately describes continuation/restart iterations too. CLI
1189
+ * flag names are preserved for backwards compatibility. Posting now uses
1190
+ * postTrackedComment so the comment ID is registered in the in-memory tool-
1191
+ * comment set — that way the next iteration's --auto-attach-solution-summary
1192
+ * check doesn't mistake a previous iteration's summary for an AI comment.
1186
1193
  *
1187
1194
  * @param {Object} options - Options object
1188
1195
  * @param {string} options.resultSummary - The AI's result summary text
@@ -1194,34 +1201,33 @@ export const checkForAiCreatedComments = async (sessionStartTime, owner, repo, p
1194
1201
  */
1195
1202
  export const attachSolutionSummary = async ({ resultSummary, prNumber, issueNumber, owner, repo }) => {
1196
1203
  if (!resultSummary || typeof resultSummary !== 'string') {
1197
- await log('⚠️ No solution summary available to attach', { verbose: true });
1204
+ await log('⚠️ No working session summary available to attach', { verbose: true });
1198
1205
  return false;
1199
1206
  }
1200
1207
 
1201
1208
  const targetNumber = prNumber || issueNumber;
1202
1209
  const targetType = prNumber ? 'pr' : 'issue';
1203
- const ghCommand = prNumber ? 'pr' : 'issue';
1204
1210
 
1205
1211
  if (!targetNumber) {
1206
- await log('⚠️ No PR or issue number to attach solution summary to', { verbose: true });
1212
+ await log('⚠️ No PR or issue number to attach working session summary to', { verbose: true });
1207
1213
  return false;
1208
1214
  }
1209
1215
 
1210
1216
  try {
1211
- const comment = `## Solution summary
1217
+ const comment = `## Working session summary
1212
1218
 
1213
1219
  ${resultSummary}
1214
1220
 
1215
1221
  ---
1216
1222
  *This summary was automatically extracted from the AI working session output.*`;
1217
1223
 
1218
- const result = await $`gh ${ghCommand} comment ${targetNumber} --repo ${owner}/${repo} --body ${comment}`;
1224
+ const { ok, commentId, stderr } = await postTrackedComment({ $, owner, repo, targetNumber, body: comment });
1219
1225
 
1220
- if (result.code === 0) {
1221
- await log(`✅ Solution summary attached to ${targetType} #${targetNumber}`);
1226
+ if (ok) {
1227
+ await log(`✅ Working session summary attached to ${targetType} #${targetNumber}${commentId ? ` (id=${commentId})` : ''}`);
1222
1228
  return true;
1223
1229
  } else {
1224
- await log(`⚠️ Failed to attach solution summary: ${result.stderr?.toString() || 'Unknown error'}`, {
1230
+ await log(`⚠️ Failed to attach working session summary: ${stderr || 'Unknown error'}`, {
1225
1231
  level: 'warning',
1226
1232
  });
1227
1233
  return false;
@@ -1231,9 +1237,78 @@ ${resultSummary}
1231
1237
  context: 'attach_solution_summary',
1232
1238
  targetType,
1233
1239
  targetNumber,
1234
- operation: 'post_solution_summary_comment',
1240
+ operation: 'post_working_session_summary_comment',
1235
1241
  });
1236
- await log(`⚠️ Error attaching solution summary: ${error.message}`, { level: 'warning' });
1242
+ await log(`⚠️ Error attaching working session summary: ${error.message}`, { level: 'warning' });
1237
1243
  return false;
1238
1244
  }
1239
1245
  };
1246
+
1247
+ /**
1248
+ * Decide whether to attach a working session summary for a single working
1249
+ * session and, if so, post it. Single source of truth for the attach decision
1250
+ * shared by every working-session call site:
1251
+ *
1252
+ * - solve.mjs (top-level, end-of-run)
1253
+ * - solve.auto-merge.lib.mjs (auto-restart-until-mergeable iterations)
1254
+ * - solve.watch.lib.mjs (watch / temporary auto-restart iterations)
1255
+ *
1256
+ * Issue #1728: Before this helper, only solve.mjs ran the attach decision, so
1257
+ * iterations inside auto-restart-until-mergeable / watch silently dropped the
1258
+ * AI's `resultSummary` whenever the AI itself posted no comment. Centralising
1259
+ * the decision here means every working session ends with either an AI-authored
1260
+ * comment OR an automated "Working session summary" comment, matching the
1261
+ * issue's "unify logic for all working sessions" requirement.
1262
+ *
1263
+ * @param {Object} options
1264
+ * @param {Object} options.argv - parsed CLI arguments (reads attachSolutionSummary
1265
+ * and autoAttachSolutionSummary; flag names preserved for backwards compat)
1266
+ * @param {string|null|undefined} options.resultSummary - AI's last-message summary
1267
+ * @param {Date} options.workStartTime - the iteration's own start time, used to
1268
+ * scope the AI-comment check to this iteration only
1269
+ * @param {string} options.owner
1270
+ * @param {string} options.repo
1271
+ * @param {number|null} options.prNumber
1272
+ * @param {number|null} options.issueNumber
1273
+ * @param {boolean} [options.success=true] - skip attachment for failed iterations
1274
+ * @returns {Promise<{attached: boolean, reason: string}>}
1275
+ */
1276
+ export const maybeAttachWorkingSessionSummary = async ({ argv, resultSummary, workStartTime, owner, repo, prNumber, issueNumber, success = true }) => {
1277
+ if (!success) {
1278
+ return { attached: false, reason: 'iteration_failed' };
1279
+ }
1280
+
1281
+ const attachFlag = argv && (argv.attachSolutionSummary || argv['attach-solution-summary']);
1282
+ const autoAttachFlag = argv && (argv.autoAttachSolutionSummary || argv['auto-attach-solution-summary']);
1283
+
1284
+ if (!attachFlag && !autoAttachFlag) {
1285
+ return { attached: false, reason: 'flag_disabled' };
1286
+ }
1287
+
1288
+ if (!resultSummary || typeof resultSummary !== 'string') {
1289
+ await log('ℹ️ No working session summary available from AI tool output', { verbose: true });
1290
+ return { attached: false, reason: 'no_result_summary' };
1291
+ }
1292
+
1293
+ let shouldAttach = false;
1294
+ if (attachFlag) {
1295
+ shouldAttach = true;
1296
+ await log('📝 --attach-solution-summary enabled, attaching working session summary...');
1297
+ } else if (autoAttachFlag) {
1298
+ await log('🔍 Checking if AI created any comments during session (--auto-attach-solution-summary)...');
1299
+ const aiCreatedComments = await checkForAiCreatedComments(workStartTime, owner, repo, prNumber, issueNumber);
1300
+ if (aiCreatedComments) {
1301
+ await log('ℹ️ AI created comments during session, skipping working session summary attachment');
1302
+ return { attached: false, reason: 'ai_comments_present' };
1303
+ }
1304
+ shouldAttach = true;
1305
+ await log('📝 No AI comments detected, attaching working session summary...');
1306
+ }
1307
+
1308
+ if (!shouldAttach) {
1309
+ return { attached: false, reason: 'no_attach_decision' };
1310
+ }
1311
+
1312
+ const ok = await attachSolutionSummary({ resultSummary, prNumber, issueNumber, owner, repo });
1313
+ return { attached: !!ok, reason: ok ? 'attached' : 'post_failed' };
1314
+ };
@@ -8,6 +8,7 @@
8
8
  // in checkForAiCreatedComments() always matches what we actually posted.
9
9
  import { AI_WORK_SESSION_STARTED_MARKER, AI_WORK_SESSION_COMPLETED_MARKER, AI_WORK_SESSION_RESUMED_MARKER, AUTO_RESUME_ON_LIMIT_RESET_MARKER, AUTO_RESTART_ON_LIMIT_RESET_MARKER, postTrackedComment } from './tool-comments.lib.mjs';
10
10
 
11
+ import { wrapDollarWithGhRetry as _wrapDollarWithGhRetry } from './github-rate-limit.lib.mjs'; // rate-limit marker (#1726): gh API calls flow through $ wrapped by caller
11
12
  /**
12
13
  * Session type definitions for different work session contexts
13
14
  * See: https://github.com/link-assistant/hive-mind/issues/1152
@@ -15,8 +15,9 @@ if (typeof globalThis.use === 'undefined') {
15
15
  const use = globalThis.use;
16
16
 
17
17
  // Use command-stream for consistent $ behavior across runtimes
18
- const { $ } = await use('command-stream');
19
-
18
+ const { $: __rawDollar$ } = await use('command-stream');
19
+ const { wrapDollarWithGhRetry } = await import('./github-rate-limit.lib.mjs');
20
+ const $ = wrapDollarWithGhRetry(__rawDollar$);
20
21
  // Import shared library functions
21
22
  const lib = await import('./lib.mjs');
22
23
  const { log, cleanErrorMessage, formatAligned, getLogFile } = lib;
@@ -45,6 +46,10 @@ const { formatAutoIterationLimit, hasReachedAutoIterationLimit, normalizeAutoIte
45
46
  const toolComments = await import('./tool-comments.lib.mjs');
46
47
  const { AUTO_RESTART_MARKER, postTrackedComment } = toolComments;
47
48
 
49
+ // Issue #1728: Per-iteration working session summary attachment helper
50
+ const resultsLib = await import('./solve.results.lib.mjs');
51
+ const { maybeAttachWorkingSessionSummary } = resultsLib;
52
+
48
53
  /**
49
54
  * Monitor for feedback in a loop and trigger restart when detected
50
55
  */
@@ -231,6 +236,10 @@ export const watchForFeedback = async params => {
231
236
  await log(formatAligned('🔄', 'Restarting:', `Re-running ${argv.tool.toUpperCase()} to handle feedback...`));
232
237
  }
233
238
 
239
+ // Issue #1728: Scope the AI-comment check that gates --auto-attach-solution-summary
240
+ // to comments posted during *this* iteration only, not across the whole watch loop.
241
+ const iterationStartTime = new Date();
242
+
234
243
  // Execute tool using shared utility
235
244
  const toolResult = await executeToolIteration({
236
245
  issueUrl,
@@ -423,6 +432,34 @@ export const watchForFeedback = async params => {
423
432
  }
424
433
  }
425
434
 
435
+ // Issue #1728: Attach a "Working session summary" comment for this
436
+ // iteration if the AI didn't post any comments of its own (and
437
+ // --auto-attach-solution-summary is enabled, which it is by default).
438
+ // Same fix as in solve.auto-merge.lib.mjs — every working session,
439
+ // not just the top-level run, should honour the auto-attach flag.
440
+ try {
441
+ await maybeAttachWorkingSessionSummary({
442
+ argv,
443
+ resultSummary: toolResult.resultSummary,
444
+ workStartTime: iterationStartTime,
445
+ owner,
446
+ repo,
447
+ prNumber,
448
+ issueNumber,
449
+ success: true,
450
+ });
451
+ } catch (summaryError) {
452
+ reportError(summaryError, {
453
+ context: 'attach_watch_working_session_summary',
454
+ prNumber,
455
+ owner,
456
+ repo,
457
+ autoRestartCount,
458
+ operation: 'attach_working_session_summary',
459
+ });
460
+ await log(formatAligned('', `⚠️ Working session summary error: ${cleanErrorMessage(summaryError)}`, '', 2));
461
+ }
462
+
426
463
  await log('');
427
464
  if (isTemporaryWatch) {
428
465
  await log(formatAligned('✅', `${argv.tool.toUpperCase()} execution completed:`, 'Checking for remaining changes...'));
@@ -18,8 +18,14 @@
18
18
 
19
19
  import { promisify } from 'util';
20
20
  import { exec as execCallback } from 'child_process';
21
+ import { ghWithRateLimitRetry } from './github-rate-limit.lib.mjs';
21
22
 
22
- const exec = promisify(execCallback);
23
+ const execRaw = promisify(execCallback);
24
+ // Issue #1726: rate-limit safe gh wrapper.
25
+ const exec = (cmd, opts) =>
26
+ ghWithRateLimitRetry(() => execRaw(cmd, opts), {
27
+ label: `gh exec (${cmd.split(/\s+/).slice(0, 3).join(' ')})`,
28
+ });
23
29
 
24
30
  /**
25
31
  * Escapes special characters in text for Telegram Markdown formatting
@@ -18,6 +18,7 @@
18
18
  import { maskToken, log, isENOSPC } from './lib.mjs';
19
19
  import { reportError } from './sentry.lib.mjs';
20
20
 
21
+ import { wrapDollarWithGhRetry as _wrapDollarWithGhRetry } from './github-rate-limit.lib.mjs'; // rate-limit marker (#1726): gh API calls flow through $ wrapped by caller
21
22
  // Dynamic imports for runtime dependencies
22
23
  const getOsModule = async () => (await import('os')).default;
23
24
  const getPathModule = async () => (await import('path')).default;
@@ -55,6 +55,17 @@ export const AUTO_MERGED_MARKER = 'Auto-merged';
55
55
  // solve.auto-merge.lib.mjs — billing-limit notification (spending cap / free tier)
56
56
  export const BILLING_LIMIT_MARKER = 'GitHub Actions Billing Limit';
57
57
 
58
+ // solve.results.lib.mjs — working session summary comments posted by
59
+ // --attach-solution-summary / --auto-attach-solution-summary at the end of
60
+ // every working session (top-level solve, auto-restart-until-mergeable
61
+ // iteration, or watch-mode iteration). Issue #1728: Renamed from
62
+ // "Solution summary" because not every working session is a solution draft —
63
+ // many are continuation/restart iterations that are part of an in-progress
64
+ // solution. Tracking it as a tool-generated marker prevents the next
65
+ // iteration's --auto-attach-solution-summary check from mistaking a
66
+ // previous iteration's summary for an AI-authored comment.
67
+ export const WORKING_SESSION_SUMMARY_MARKER = 'Working session summary';
68
+
58
69
  // github.lib.mjs — fork contributor "Allow edits by maintainers" request
59
70
  export const MAINTAINER_ACCESS_REQUEST_MARKER = 'Allow edits by maintainers';
60
71
 
@@ -88,7 +99,7 @@ export const USAGE_LIMIT_REACHED_MARKER = 'Usage Limit Reached';
88
99
  * named constants above so that adding a new marker only requires adding
89
100
  * the constant and appending it here.
90
101
  */
91
- export const TOOL_GENERATED_COMMENT_MARKERS = [AI_WORK_SESSION_STARTED_MARKER, AI_WORK_SESSION_COMPLETED_MARKER, AI_WORK_SESSION_RESUMED_MARKER, AUTO_RESUME_ON_LIMIT_RESET_MARKER, AUTO_RESTART_ON_LIMIT_RESET_MARKER, SOLUTION_DRAFT_LOG_MARKER, AUTO_RESTART_MARKER, AUTO_RESTART_UNTIL_MERGEABLE_LOG_MARKER, READY_TO_MERGE_MARKER, AUTO_MERGED_MARKER, BILLING_LIMIT_MARKER, MAINTAINER_ACCESS_REQUEST_MARKER, LIVE_PROGRESS_SECTION_START_MARKER, SESSION_FORCE_KILLED_MARKER, REPOSITORY_INITIALIZATION_REQUIRED_MARKER, INTERACTIVE_SESSION_STARTED_MARKER, INTERACTIVE_SESSION_ENDED_MARKER, NOW_WORKING_SESSION_IS_ENDED_MARKER, SOLUTION_DRAFT_FAILED_MARKER, SOLUTION_DRAFT_FINISHED_WITH_ERRORS_MARKER, USAGE_LIMIT_REACHED_MARKER];
102
+ export const TOOL_GENERATED_COMMENT_MARKERS = [AI_WORK_SESSION_STARTED_MARKER, AI_WORK_SESSION_COMPLETED_MARKER, AI_WORK_SESSION_RESUMED_MARKER, AUTO_RESUME_ON_LIMIT_RESET_MARKER, AUTO_RESTART_ON_LIMIT_RESET_MARKER, SOLUTION_DRAFT_LOG_MARKER, AUTO_RESTART_MARKER, AUTO_RESTART_UNTIL_MERGEABLE_LOG_MARKER, READY_TO_MERGE_MARKER, AUTO_MERGED_MARKER, BILLING_LIMIT_MARKER, MAINTAINER_ACCESS_REQUEST_MARKER, LIVE_PROGRESS_SECTION_START_MARKER, SESSION_FORCE_KILLED_MARKER, REPOSITORY_INITIALIZATION_REQUIRED_MARKER, INTERACTIVE_SESSION_STARTED_MARKER, INTERACTIVE_SESSION_ENDED_MARKER, NOW_WORKING_SESSION_IS_ENDED_MARKER, SOLUTION_DRAFT_FAILED_MARKER, SOLUTION_DRAFT_FINISHED_WITH_ERRORS_MARKER, USAGE_LIMIT_REACHED_MARKER, WORKING_SESSION_SUMMARY_MARKER];
92
103
 
93
104
  /**
94
105
  * Markers that indicate the end of a working session. Used by
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { wrapDollarWithGhRetry as _wrapDollarWithGhRetry } from '../github-rate-limit.lib.mjs'; // rate-limit marker (#1726): gh API calls flow through $ wrapped by caller
2
3
 
3
4
  /**
4
5
  * YouTrack to GitHub Issue Synchronization Module