@link-assistant/hive-mind 1.24.2 → 1.24.3

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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.24.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 297e07c: Fix incorrect iteration counter and duplicate comments in auto-restart mode
8
+ - Fixed iteration counter to show actual AI restart count instead of check cycle number
9
+ - Added deduplication check to prevent duplicate "Ready to merge" status comments
10
+ - Added case study documentation for issue #1323
11
+
3
12
  ## 1.24.2
4
13
 
5
14
  ### Patch Changes
package/README.md CHANGED
@@ -811,9 +811,21 @@ procinfo 62220
811
811
 
812
812
  ## Maintenance
813
813
 
814
- ### Reboot server.
814
+ ### Enter latest screen
815
+
816
+ ```bash
817
+ s=$(screen -ls | awk '/Detached/ {print $1; exit}'); echo "Entering $s"; screen -r "$s"; echo "Left $s";
818
+ ```
819
+
820
+ ### Enter oldest screen
815
821
 
822
+ ```bash
823
+ s=$(screen -ls | awk '/Detached/ {last=$1} END{print last}'); echo "Entering $s"; screen -r "$s"; echo "Left $s";
816
824
  ```
825
+
826
+ ### Reboot server.
827
+
828
+ ```bash
817
829
  sudo reboot
818
830
  ```
819
831
 
@@ -821,7 +833,7 @@ That will remove all dangling unused proccesses and screens, which will in turn
821
833
 
822
834
  ### Cleanup disk space.
823
835
 
824
- ```
836
+ ```bash
825
837
  df -h
826
838
 
827
839
  rm -rf /tmp
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.24.2",
3
+ "version": "1.24.3",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -43,6 +43,37 @@ const { sanitizeLogContent, attachLogToGitHub } = githubLib;
43
43
  const restartShared = await import('./solve.restart-shared.lib.mjs');
44
44
  const { checkPRMerged, checkPRClosed, checkForUncommittedChanges, getUncommittedChangesDetails, executeToolIteration, buildAutoRestartInstructions, isApiError } = restartShared;
45
45
 
46
+ /**
47
+ * Issue #1323: Check if a comment with specific content already exists on the PR
48
+ * This prevents duplicate status comments when multiple processes or restarts occur
49
+ * @param {string} owner - Repository owner
50
+ * @param {string} repo - Repository name
51
+ * @param {number} prNumber - Pull request number
52
+ * @param {string} commentSignature - Unique signature to search for in comment body (e.g., "✅ Ready to merge")
53
+ * @param {boolean} verbose - Enable verbose logging
54
+ * @returns {Promise<boolean>} - True if a matching comment already exists
55
+ */
56
+ const checkForExistingComment = async (owner, repo, prNumber, commentSignature, verbose = false) => {
57
+ try {
58
+ // Fetch recent PR comments (last 20 to avoid fetching entire history)
59
+ const result = await $`gh api repos/${owner}/${repo}/issues/${prNumber}/comments --jq '.[].body' 2>/dev/null`;
60
+ if (result.code === 0 && result.stdout) {
61
+ const bodies = result.stdout.toString();
62
+ const hasMatch = bodies.includes(commentSignature);
63
+ if (verbose && hasMatch) {
64
+ console.log(`[VERBOSE] Found existing comment with signature: "${commentSignature}"`);
65
+ }
66
+ return hasMatch;
67
+ }
68
+ } catch (error) {
69
+ // If check fails, allow posting to avoid silent failures
70
+ if (verbose) {
71
+ console.log(`[VERBOSE] Failed to check for existing comment: ${error.message}`);
72
+ }
73
+ }
74
+ return false;
75
+ };
76
+
46
77
  /**
47
78
  * Check for new comments from non-bot users since last commit
48
79
  * @returns {Promise<{hasNewComments: boolean, comments: Array}>}
@@ -258,6 +289,11 @@ export const watchUntilMergeable = async params => {
258
289
  let latestSessionId = null;
259
290
  let latestAnthropicCost = null;
260
291
 
292
+ // Issue #1323: Track actual restart count separately from check cycle iteration
293
+ // `iteration` counts check cycles (how many times we check for blockers)
294
+ // `restartCount` counts actual AI tool executions (when we actually restart the AI)
295
+ let restartCount = 0;
296
+
261
297
  // Track consecutive API errors for retry limit
262
298
  const MAX_API_ERROR_RETRIES = 3;
263
299
  let consecutiveApiErrors = 0;
@@ -344,10 +380,17 @@ export const watchUntilMergeable = async params => {
344
380
  await log(formatAligned('', 'PR is ready to be merged manually', '', 2));
345
381
  await log(formatAligned('', 'Exiting auto-restart-until-mergeable mode', '', 2));
346
382
 
347
- // Post success comment
383
+ // Issue #1323: Post success comment only if one doesn't already exist
384
+ // This prevents duplicate comments when multiple processes reach this point
348
385
  try {
349
- const commentBody = `## ✅ Ready to merge\n\nThis pull request is now ready to be merged:\n- All CI checks have passed\n- No merge conflicts\n- No pending changes\n\n---\n*Monitored by hive-mind with --auto-restart-until-mergeable flag*`;
350
- await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${commentBody}`;
386
+ const readyToMergeSignature = '## ✅ Ready to merge';
387
+ const hasExistingComment = await checkForExistingComment(owner, repo, prNumber, readyToMergeSignature, argv.verbose);
388
+ if (!hasExistingComment) {
389
+ const commentBody = `## ✅ Ready to merge\n\nThis pull request is now ready to be merged:\n- All CI checks have passed\n- No merge conflicts\n- No pending changes\n\n---\n*Monitored by hive-mind with --auto-restart-until-mergeable flag*`;
390
+ await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${commentBody}`;
391
+ } else {
392
+ await log(formatAligned('', 'Skipping duplicate "Ready to merge" comment', '', 2));
393
+ }
351
394
  } catch {
352
395
  // Don't fail if comment posting fails
353
396
  }
@@ -518,10 +561,14 @@ Once the billing issue is resolved, you can re-run the CI checks or push a new c
518
561
  }
519
562
 
520
563
  if (shouldRestart) {
564
+ // Issue #1323: Increment restart count (actual AI executions, not check cycles)
565
+ restartCount++;
566
+
521
567
  // Add standard instructions for auto-restart-until-mergeable mode using shared utility
522
568
  feedbackLines.push(...buildAutoRestartInstructions());
523
569
 
524
570
  await log(formatAligned('🔄', 'RESTART TRIGGERED:', restartReason));
571
+ await log(formatAligned('', 'Restart iteration:', `${restartCount}`, 2));
525
572
  await log('');
526
573
 
527
574
  // Post a comment to PR about the restart
@@ -601,7 +648,8 @@ Once the billing issue is resolved, you can re-run the CI checks or push a new c
601
648
  try {
602
649
  const logFile = getLogFile();
603
650
  if (logFile) {
604
- const customTitle = `🔄 Auto-restart-until-mergeable Log (iteration ${iteration})`;
651
+ // Issue #1323: Use restartCount (actual AI executions) instead of iteration (check cycles)
652
+ const customTitle = `🔄 Auto-restart-until-mergeable Log (iteration ${restartCount})`;
605
653
  await attachLogToGitHub({
606
654
  logFile,
607
655
  targetType: 'pr',
@@ -779,11 +827,17 @@ export const startAutoRestartUntilMergeable = async params => {
779
827
  await log(formatAligned('', 'Action:', 'PR is ready for manual merge by a repository maintainer', 2));
780
828
  await log('');
781
829
 
782
- // Post a comment to the PR notifying the maintainer
830
+ // Issue #1323: Post a comment to the PR notifying the maintainer (with deduplication)
783
831
  try {
784
- const commentBody = `## ✅ Ready to merge\n\nThis pull request is ready to be merged. Auto-merge was requested (\`--auto-merge\`) but cannot be performed because this PR was created from a fork (no write access to the target repository).\n\nPlease merge manually.\n\n---\n*hive-mind with --auto-merge flag (fork mode)*`;
785
- await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${commentBody}`;
786
- await log(formatAligned('', '💬 Posted merge readiness notification to PR', '', 2));
832
+ const readyToMergeSignature = '## ✅ Ready to merge';
833
+ const hasExistingComment = await checkForExistingComment(owner, repo, prNumber, readyToMergeSignature, argv.verbose);
834
+ if (!hasExistingComment) {
835
+ const commentBody = `## ✅ Ready to merge\n\nThis pull request is ready to be merged. Auto-merge was requested (\`--auto-merge\`) but cannot be performed because this PR was created from a fork (no write access to the target repository).\n\nPlease merge manually.\n\n---\n*hive-mind with --auto-merge flag (fork mode)*`;
836
+ await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${commentBody}`;
837
+ await log(formatAligned('', '💬 Posted merge readiness notification to PR', '', 2));
838
+ } else {
839
+ await log(formatAligned('', 'Skipping duplicate "Ready to merge" comment', '', 2));
840
+ }
787
841
  } catch {
788
842
  // Don't fail if comment posting fails
789
843
  }
@@ -802,11 +856,17 @@ export const startAutoRestartUntilMergeable = async params => {
802
856
  await log(formatAligned('', 'Action:', 'PR is ready for manual merge by a repository maintainer', 2));
803
857
  await log('');
804
858
 
805
- // Post a comment to the PR notifying the maintainer
859
+ // Issue #1323: Post a comment to the PR notifying the maintainer (with deduplication)
806
860
  try {
807
- const commentBody = `## ✅ Ready to merge\n\nThis pull request is ready to be merged. Auto-merge was requested (\`--auto-merge\`) but cannot be performed because the authenticated user lacks write access to \`${owner}/${repo}\` (current permission: \`${permission || 'unknown'}\`).\n\nPlease merge manually.\n\n---\n*hive-mind with --auto-merge flag*`;
808
- await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${commentBody}`;
809
- await log(formatAligned('', '💬 Posted merge readiness notification to PR', '', 2));
861
+ const readyToMergeSignature = '## ✅ Ready to merge';
862
+ const hasExistingComment = await checkForExistingComment(owner, repo, prNumber, readyToMergeSignature, argv.verbose);
863
+ if (!hasExistingComment) {
864
+ const commentBody = `## ✅ Ready to merge\n\nThis pull request is ready to be merged. Auto-merge was requested (\`--auto-merge\`) but cannot be performed because the authenticated user lacks write access to \`${owner}/${repo}\` (current permission: \`${permission || 'unknown'}\`).\n\nPlease merge manually.\n\n---\n*hive-mind with --auto-merge flag*`;
865
+ await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${commentBody}`;
866
+ await log(formatAligned('', '💬 Posted merge readiness notification to PR', '', 2));
867
+ } else {
868
+ await log(formatAligned('', 'Skipping duplicate "Ready to merge" comment', '', 2));
869
+ }
810
870
  } catch {
811
871
  // Don't fail if comment posting fails
812
872
  }