@link-assistant/hive-mind 1.11.5 → 1.12.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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 8393f99: Improve auto-resume-on-limit-reset functionality
8
+ - Add 5-minute buffer after limit reset to account for server time differences (configurable via HIVE_MIND_LIMIT_RESET_BUFFER_MS)
9
+ - Add --auto-restart-on-limit-reset option for fresh start without previous session context
10
+ - Remove CLI commands from GitHub comments when auto-resume is active (less confusing for users)
11
+ - Differentiate work session comments: "Auto Resume (on limit reset)" vs "Auto Restart (on limit reset)"
12
+ - Differentiate solution draft log comments based on session type
13
+ - Improve reset time formatting with relative time + UTC (e.g., "in 1h 23m (Jan 15, 7:00 AM UTC)")
14
+
15
+ ## 1.11.6
16
+
17
+ ### Patch Changes
18
+
19
+ - 5eef9e4: Skip Claude API limits for --tool agent tasks in queue
20
+ - Agent tools (Grok Code, OpenCode Zen) use different backends with their own rate limits
21
+ - Add tool parameter to canStartCommand() and checkApiLimits() functions
22
+ - Skip Claude-specific limits (5-hour session, weekly) when tool is 'agent'
23
+ - Consumer loop now passes next queue item's tool to limit checks
24
+ - Add 7 new tests for tool-specific limit handling
25
+ - Add case study documentation
26
+
27
+ Fixes #1159
28
+
3
29
  ## 1.11.5
4
30
 
5
31
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.11.5",
3
+ "version": "1.12.0",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -56,6 +56,14 @@ export const autoContinue = {
56
56
  ageThresholdHours: parseIntWithDefault('HIVE_MIND_AUTO_CONTINUE_AGE_HOURS', 24),
57
57
  };
58
58
 
59
+ // Auto-resume on limit reset configurations
60
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
61
+ export const limitReset = {
62
+ // Buffer time to wait after limit reset (in milliseconds)
63
+ // Default: 5 minutes - accounts for server time differences
64
+ bufferMs: parseIntWithDefault('HIVE_MIND_LIMIT_RESET_BUFFER_MS', 5 * 60 * 1000),
65
+ };
66
+
59
67
  // GitHub API limits
60
68
  export const githubLimits = {
61
69
  commentMaxSize: parseIntWithDefault('HIVE_MIND_GITHUB_COMMENT_MAX_SIZE', 65536),
@@ -377,6 +377,13 @@ export async function attachLogToGitHub(options) {
377
377
  limitResetTime = null,
378
378
  toolName = 'AI tool',
379
379
  resumeCommand = null,
380
+ // Whether auto-resume/auto-restart is enabled (determines if CLI commands should be shown)
381
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
382
+ isAutoResumeEnabled = false,
383
+ autoResumeMode = 'resume', // 'resume' or 'restart'
384
+ // Session type for differentiating solution draft log comments
385
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
386
+ sessionType = 'new', // 'new', 'resume', 'auto-resume', 'auto-restart'
380
387
  // New parameters for agent tool pricing support
381
388
  publicPricingEstimate = null,
382
389
  pricingInfo = null,
@@ -457,21 +464,35 @@ The automated solution draft was interrupted because the ${toolName} usage limit
457
464
 
458
465
  logComment += '\n\n### šŸ”„ How to Continue\n';
459
466
 
460
- if (limitResetTime) {
461
- logComment += `Once the limit resets at **${limitResetTime}**, `;
467
+ // If auto-resume/auto-restart is enabled, show automatic continuation message instead of CLI commands
468
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
469
+ if (isAutoResumeEnabled) {
470
+ const modeName = autoResumeMode === 'restart' ? 'restart' : 'resume';
471
+ const modeDescription = autoResumeMode === 'restart' ? 'The session will automatically restart (fresh start) when the limit resets.' : 'The session will automatically resume (with context preserved) when the limit resets.';
472
+
473
+ if (limitResetTime) {
474
+ logComment += `**Auto-${modeName} is enabled.** ${modeDescription}`;
475
+ } else {
476
+ logComment += `**Auto-${modeName} is enabled.** ${modeDescription}`;
477
+ }
462
478
  } else {
463
- logComment += 'Once the limit resets, ';
464
- }
479
+ // Manual resume mode - show CLI commands
480
+ if (limitResetTime) {
481
+ logComment += `Once the limit resets at **${limitResetTime}**, `;
482
+ } else {
483
+ logComment += 'Once the limit resets, ';
484
+ }
465
485
 
466
- if (resumeCommand) {
467
- logComment += `you can resume this session by running:
486
+ if (resumeCommand) {
487
+ logComment += `you can resume this session by running:
468
488
  \`\`\`bash
469
489
  ${resumeCommand}
470
490
  \`\`\``;
471
- } else if (sessionId) {
472
- logComment += `you can resume this session using session ID: \`${sessionId}\``;
473
- } else {
474
- logComment += 'you can retry the operation.';
491
+ } else if (sessionId) {
492
+ logComment += `you can resume this session using session ID: \`${sessionId}\``;
493
+ } else {
494
+ logComment += 'you can retry the operation.';
495
+ }
475
496
  }
476
497
 
477
498
  logComment += `
@@ -528,8 +549,22 @@ ${logContent}
528
549
  } else {
529
550
  // Success log format - use helper function for cost info
530
551
  const costInfo = buildCostInfoString(totalCostUSD, anthropicTotalCostUSD, pricingInfo);
531
- logComment = `## ${customTitle}
532
- This log file contains the complete execution trace of the AI ${targetType === 'pr' ? 'solution draft' : 'analysis'} process.${costInfo}
552
+ // Determine title based on session type
553
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
554
+ let title = customTitle;
555
+ let sessionNote = '';
556
+ if (sessionType === 'auto-resume') {
557
+ title = 'šŸ”„ Draft log of auto resume (on limit reset)';
558
+ sessionNote = '\n\n**Note**: This session was automatically resumed after a usage limit reset, with the previous context preserved.';
559
+ } else if (sessionType === 'auto-restart') {
560
+ title = 'šŸ”„ Draft log of auto restart (on limit reset)';
561
+ sessionNote = '\n\n**Note**: This session was automatically restarted after a usage limit reset (fresh start).';
562
+ } else if (sessionType === 'resume') {
563
+ title = 'šŸ”„ Solution Draft Log (Resumed)';
564
+ sessionNote = '\n\n**Note**: This session was manually resumed using the --resume flag.';
565
+ }
566
+ logComment = `## ${title}
567
+ This log file contains the complete execution trace of the AI ${targetType === 'pr' ? 'solution draft' : 'analysis'} process.${costInfo}${sessionNote}
533
568
 
534
569
  <details>
535
570
  <summary>Click to expand solution draft log (${Math.round(logStats.size / 1024)}KB)</summary>
@@ -622,21 +657,31 @@ The automated solution draft was interrupted because the ${toolName} usage limit
622
657
 
623
658
  logUploadComment += '\n\n### šŸ”„ How to Continue\n';
624
659
 
625
- if (limitResetTime) {
626
- logUploadComment += `Once the limit resets at **${limitResetTime}**, `;
627
- } else {
628
- logUploadComment += 'Once the limit resets, ';
629
- }
660
+ // If auto-resume/auto-restart is enabled, show automatic continuation message instead of CLI commands
661
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
662
+ if (isAutoResumeEnabled) {
663
+ const modeName = autoResumeMode === 'restart' ? 'restart' : 'resume';
664
+ const modeDescription = autoResumeMode === 'restart' ? 'The session will automatically restart (fresh start) when the limit resets.' : 'The session will automatically resume (with context preserved) when the limit resets.';
630
665
 
631
- if (resumeCommand) {
632
- logUploadComment += `you can resume this session by running:
666
+ logUploadComment += `**Auto-${modeName} is enabled.** ${modeDescription}`;
667
+ } else {
668
+ // Manual resume mode - show CLI commands
669
+ if (limitResetTime) {
670
+ logUploadComment += `Once the limit resets at **${limitResetTime}**, `;
671
+ } else {
672
+ logUploadComment += 'Once the limit resets, ';
673
+ }
674
+
675
+ if (resumeCommand) {
676
+ logUploadComment += `you can resume this session by running:
633
677
  \`\`\`bash
634
678
  ${resumeCommand}
635
679
  \`\`\``;
636
- } else if (sessionId) {
637
- logUploadComment += `you can resume this session using session ID: \`${sessionId}\``;
638
- } else {
639
- logUploadComment += 'you can retry the operation.';
680
+ } else if (sessionId) {
681
+ logUploadComment += `you can resume this session using session ID: \`${sessionId}\``;
682
+ } else {
683
+ logUploadComment += 'you can retry the operation.';
684
+ }
640
685
  }
641
686
 
642
687
  logUploadComment += `
@@ -672,9 +717,23 @@ This log file contains the complete execution trace of the AI ${targetType === '
672
717
  } else {
673
718
  // Success log format - use helper function for cost info
674
719
  const costInfo = buildCostInfoString(totalCostUSD, anthropicTotalCostUSD, pricingInfo);
675
- logUploadComment = `## ${customTitle}
720
+ // Determine title based on session type
721
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
722
+ let title = customTitle;
723
+ let sessionNote = '';
724
+ if (sessionType === 'auto-resume') {
725
+ title = 'šŸ”„ Draft log of auto resume (on limit reset)';
726
+ sessionNote = '\n**Note**: This session was automatically resumed after a usage limit reset, with the previous context preserved.\n';
727
+ } else if (sessionType === 'auto-restart') {
728
+ title = 'šŸ”„ Draft log of auto restart (on limit reset)';
729
+ sessionNote = '\n**Note**: This session was automatically restarted after a usage limit reset (fresh start).\n';
730
+ } else if (sessionType === 'resume') {
731
+ title = 'šŸ”„ Solution Draft Log (Resumed)';
732
+ sessionNote = '\n**Note**: This session was manually resumed using the --resume flag.\n';
733
+ }
734
+ logUploadComment = `## ${title}
676
735
  This log file contains the complete execution trace of the AI ${targetType === 'pr' ? 'solution draft' : 'analysis'} process.${costInfo}
677
- šŸ“Ž **Log file uploaded as ${uploadTypeLabel}${chunkInfo}** (${Math.round(logStats.size / 1024)}KB)
736
+ ${sessionNote}šŸ“Ž **Log file uploaded as ${uploadTypeLabel}${chunkInfo}** (${Math.round(logStats.size / 1024)}KB)
678
737
  šŸ”— [View complete solution draft log](${logUrl})
679
738
  ---
680
739
  *Now working session is ended, feel free to review and add any feedback on the solution draft.*`;
@@ -33,6 +33,11 @@ const { checkFileInBranch } = githubLib;
33
33
  // Import validation functions for time parsing
34
34
  const validation = await import('./solve.validation.lib.mjs');
35
35
 
36
+ // Import usage limit formatting functions
37
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
38
+ const usageLimitLib = await import('./usage-limit.lib.mjs');
39
+ const { formatResetTimeWithRelative } = usageLimitLib;
40
+
36
41
  // Import Sentry integration
37
42
  const sentryLib = await import('./sentry.lib.mjs');
38
43
  const { reportError } = sentryLib;
@@ -42,7 +47,7 @@ const githubLinking = await import('./github-linking.lib.mjs');
42
47
  const { extractLinkedIssueNumber } = githubLinking;
43
48
 
44
49
  // Import configuration
45
- import { autoContinue } from './config.lib.mjs';
50
+ import { autoContinue, limitReset } from './config.lib.mjs';
46
51
 
47
52
  const { calculateWaitTime } = validation;
48
53
 
@@ -67,13 +72,27 @@ const formatWaitTime = ms => {
67
72
  // Auto-continue function that waits until limit resets
68
73
  // tempDir parameter is required for passing --working-directory to the resumed session
69
74
  // (Claude Code sessions are stored per-working-directory, so resume must use same directory)
70
- export const autoContinueWhenLimitResets = async (issueUrl, sessionId, argv, shouldAttachLogs, tempDir = null) => {
75
+ // isRestart parameter distinguishes between resume (maintains context) and restart (fresh start)
76
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
77
+ export const autoContinueWhenLimitResets = async (issueUrl, sessionId, argv, shouldAttachLogs, tempDir = null, isRestart = false) => {
71
78
  try {
72
79
  const resetTime = global.limitResetTime;
73
- const waitMs = calculateWaitTime(resetTime);
74
-
75
- await log(`\nā° Waiting until ${resetTime} for limit to reset...`);
76
- await log(` Wait time: ${formatWaitTime(waitMs)}`);
80
+ const timezone = global.limitTimezone || null;
81
+ const baseWaitMs = calculateWaitTime(resetTime);
82
+
83
+ // Add buffer time after limit reset to account for server time differences
84
+ // Default: 5 minutes (configurable via HIVE_MIND_LIMIT_RESET_BUFFER_MS)
85
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
86
+ const bufferMs = limitReset.bufferMs;
87
+ const waitMs = baseWaitMs + bufferMs;
88
+ const bufferMinutes = Math.round(bufferMs / 60000);
89
+
90
+ // Format reset time with relative time and UTC for better user understanding
91
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
92
+ const formattedResetTime = formatResetTimeWithRelative(resetTime, timezone);
93
+
94
+ await log(`\nā° Waiting until ${formattedResetTime} + ${bufferMinutes} min buffer for limit to reset...`);
95
+ await log(` Wait time: ${formatWaitTime(waitMs)} (includes ${bufferMinutes} min buffer for server time differences)`);
77
96
  await log(` Current time: ${new Date().toLocaleTimeString()}`);
78
97
 
79
98
  // Show countdown every 30 minutes for long waits, every minute for short waits
@@ -83,7 +102,7 @@ export const autoContinueWhenLimitResets = async (issueUrl, sessionId, argv, sho
83
102
  const countdownTimer = setInterval(async () => {
84
103
  remainingMs -= countdownInterval;
85
104
  if (remainingMs > 0) {
86
- await log(`ā³ Time remaining: ${formatWaitTime(remainingMs)} until ${resetTime}`);
105
+ await log(`ā³ Time remaining: ${formatWaitTime(remainingMs)} until ${formattedResetTime}`);
87
106
  }
88
107
  }, countdownInterval);
89
108
 
@@ -91,25 +110,42 @@ export const autoContinueWhenLimitResets = async (issueUrl, sessionId, argv, sho
91
110
  await new Promise(resolve => setTimeout(resolve, waitMs));
92
111
  clearInterval(countdownTimer);
93
112
 
94
- await log('\nāœ… Limit reset time reached! Resuming session...');
113
+ const actionType = isRestart ? 'Restarting' : 'Resuming';
114
+ await log(`\nāœ… Limit reset time reached (+ ${bufferMinutes} min buffer)! ${actionType} session...`);
95
115
  await log(` Current time: ${new Date().toLocaleTimeString()}`);
96
116
 
97
- // Recursively call the solve script with --resume
98
- // We need to reconstruct the command with appropriate flags
117
+ // Recursively call the solve script
118
+ // For resume: use --resume with session ID to maintain context
119
+ // For restart: don't use --resume to start fresh
120
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
99
121
  const childProcess = await import('child_process');
100
122
 
101
- // Build the resume command
123
+ // Build the resume/restart command
102
124
  const resumeArgs = [
103
125
  process.argv[1], // solve.mjs path
104
126
  issueUrl,
105
- '--resume',
106
- sessionId,
107
127
  ];
108
128
 
109
- // Preserve auto-resume flag
129
+ // Only include --resume if this is a true resume (not a restart)
130
+ if (!isRestart && sessionId) {
131
+ resumeArgs.push('--resume', sessionId);
132
+ await log(`šŸ”„ Session will be RESUMED with session ID: ${sessionId}`);
133
+ } else {
134
+ await log(`šŸ”„ Session will be RESTARTED (fresh start without previous context)`);
135
+ }
136
+
137
+ // Preserve auto-resume/auto-restart flag for subsequent limit hits
110
138
  if (argv.autoResumeOnLimitReset) {
111
139
  resumeArgs.push('--auto-resume-on-limit-reset');
112
140
  }
141
+ if (argv.autoRestartOnLimitReset) {
142
+ resumeArgs.push('--auto-restart-on-limit-reset');
143
+ }
144
+
145
+ // Pass session type for proper comment differentiation
146
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
147
+ const sessionType = isRestart ? 'auto-restart' : 'auto-resume';
148
+ resumeArgs.push('--session-type', sessionType);
113
149
 
114
150
  // Preserve other flags from original invocation
115
151
  if (argv.model !== 'sonnet') resumeArgs.push('--model', argv.model);
@@ -123,7 +159,7 @@ export const autoContinueWhenLimitResets = async (issueUrl, sessionId, argv, sho
123
159
  if (tempDir) {
124
160
  resumeArgs.push('--working-directory', tempDir);
125
161
  await log(`šŸ“‚ Using working directory for session continuity: ${tempDir}`);
126
- } else {
162
+ } else if (!isRestart) {
127
163
  await log(`āš ļø Warning: No working directory specified - session resume may fail`);
128
164
  await log(` Claude Code sessions are stored per-directory, consider using --working-directory`);
129
165
  }
@@ -160,9 +160,21 @@ export const createYargsConfig = yargsInstance => {
160
160
  })
161
161
  .option('auto-resume-on-limit-reset', {
162
162
  type: 'boolean',
163
- description: 'Automatically resume when AI tool limit resets (calculates reset time and waits)',
163
+ description: 'Automatically resume when AI tool limit resets (maintains session context with --resume flag)',
164
164
  default: false,
165
165
  })
166
+ .option('auto-restart-on-limit-reset', {
167
+ type: 'boolean',
168
+ description: 'Automatically restart when AI tool limit resets (fresh start without --resume flag)',
169
+ default: false,
170
+ })
171
+ .option('session-type', {
172
+ type: 'string',
173
+ description: 'Internal: Session type for comment differentiation (new, resume, auto-resume, auto-restart)',
174
+ choices: ['new', 'resume', 'auto-resume', 'auto-restart'],
175
+ default: 'new',
176
+ hidden: true,
177
+ })
166
178
  .option('auto-resume-on-errors', {
167
179
  type: 'boolean',
168
180
  description: 'Automatically resume on network errors (503, etc.) with exponential backoff',
package/src/solve.mjs CHANGED
@@ -85,7 +85,7 @@ const { setupRepositoryAndClone, verifyDefaultBranchAndStatus } = repoSetupLib;
85
85
  const branchLib = await import('./solve.branch.lib.mjs');
86
86
  const { createOrCheckoutBranch } = branchLib;
87
87
  const sessionLib = await import('./solve.session.lib.mjs');
88
- const { startWorkSession, endWorkSession } = sessionLib;
88
+ const { startWorkSession, endWorkSession, SESSION_TYPES } = sessionLib;
89
89
  const preparationLib = await import('./solve.preparation.lib.mjs');
90
90
  const { prepareFeedbackAndTimestamps, checkUncommittedChanges, checkForkActions } = preparationLib;
91
91
 
@@ -688,6 +688,16 @@ try {
688
688
  // This includes PR URL (if created) and comment info (if in continue mode)
689
689
 
690
690
  // Start work session using the new module
691
+ // Determine session type based on command line flags
692
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
693
+ let sessionType = SESSION_TYPES.NEW;
694
+ if (argv.sessionType) {
695
+ // Session type was explicitly set (e.g., by auto-resume/auto-restart spawning a new process)
696
+ sessionType = argv.sessionType;
697
+ } else if (isContinueMode) {
698
+ // Continue mode is a manual resume via PR URL
699
+ sessionType = SESSION_TYPES.RESUME;
700
+ }
691
701
  await startWorkSession({
692
702
  isContinueMode,
693
703
  prNumber,
@@ -695,6 +705,7 @@ try {
695
705
  log,
696
706
  formatAligned,
697
707
  $,
708
+ sessionType,
698
709
  });
699
710
 
700
711
  // Prepare feedback and timestamps using the new module
@@ -910,21 +921,29 @@ try {
910
921
 
911
922
  // Handle limit reached scenario
912
923
  if (limitReached) {
924
+ // Check for both auto-resume (maintains context) and auto-restart (fresh start)
925
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
913
926
  const shouldAutoResumeOnReset = argv.autoResumeOnLimitReset;
927
+ const shouldAutoRestartOnReset = argv.autoRestartOnLimitReset;
928
+ const shouldAutoContinueOnReset = shouldAutoResumeOnReset || shouldAutoRestartOnReset;
914
929
 
915
- // If limit was reached but auto-resume-on-limit-reset is NOT enabled, fail immediately
916
- if (!shouldAutoResumeOnReset) {
930
+ // If limit was reached but neither auto-resume nor auto-restart is enabled, fail immediately
931
+ if (!shouldAutoContinueOnReset) {
917
932
  await log('\nāŒ USAGE LIMIT REACHED!');
918
933
  await log(' The AI tool has reached its usage limit.');
919
934
 
920
935
  // Always show manual resume command in console so users can resume after limit resets
921
936
  if (sessionId) {
922
937
  const resetTime = global.limitResetTime;
938
+ const timezone = global.limitTimezone || null;
923
939
  await log('');
924
940
  await log(`šŸ“ Working directory: ${tempDir}`);
925
941
  await log(`šŸ“Œ Session ID: ${sessionId}`);
926
942
  if (resetTime) {
927
- await log(`ā° Limit resets at: ${resetTime}`);
943
+ // Format reset time with relative time and UTC for better user understanding
944
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
945
+ const formattedResetTime = formatResetTimeWithRelative(resetTime, timezone);
946
+ await log(`ā° Limit resets at: ${formattedResetTime}`);
928
947
  }
929
948
  await log('');
930
949
  // Show claude resume command only for --tool claude (or default)
@@ -993,15 +1012,17 @@ try {
993
1012
  }
994
1013
  }
995
1014
 
996
- await safeExit(1, 'Usage limit reached - use --auto-resume-on-limit-reset to wait for reset');
1015
+ await safeExit(1, 'Usage limit reached - use --auto-resume-on-limit-reset or --auto-restart-on-limit-reset to wait for reset');
997
1016
  } else {
998
- // auto-resume-on-limit-reset is enabled - attach logs and/or post waiting comment
1017
+ // auto-resume-on-limit-reset or auto-restart-on-limit-reset is enabled - attach logs and/or post waiting comment
1018
+ // Determine the mode type for comment formatting
1019
+ const limitContinueMode = shouldAutoRestartOnReset ? 'restart' : 'resume';
999
1020
  if (prNumber && global.limitResetTime) {
1000
1021
  // If --attach-logs is enabled, upload logs with usage limit details
1001
1022
  if (shouldAttachLogs && sessionId) {
1002
1023
  await log('\nšŸ“„ Attaching logs to Pull Request (auto-continue mode)...');
1003
1024
  try {
1004
- // Build Claude CLI resume command
1025
+ // Build Claude CLI resume command (only for logging, not shown to users when auto-resume is enabled)
1005
1026
  const tool = argv.tool || 'claude';
1006
1027
  const resumeCommand = tool === 'claude' ? buildClaudeResumeCommand({ tempDir, sessionId, model: argv.model }) : null;
1007
1028
  const logUploadSuccess = await attachLogToGitHub({
@@ -1019,6 +1040,10 @@ try {
1019
1040
  toolName: (argv.tool || 'AI tool').toString().toLowerCase() === 'claude' ? 'Claude' : (argv.tool || 'AI tool').toString().toLowerCase() === 'codex' ? 'Codex' : (argv.tool || 'AI tool').toString().toLowerCase() === 'opencode' ? 'OpenCode' : (argv.tool || 'AI tool').toString().toLowerCase() === 'agent' ? 'Agent' : 'AI tool',
1020
1041
  resumeCommand,
1021
1042
  sessionId,
1043
+ // Tell attachLogToGitHub that auto-resume is enabled to suppress CLI commands in the comment
1044
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
1045
+ isAutoResumeEnabled: true,
1046
+ autoResumeMode: limitContinueMode,
1022
1047
  });
1023
1048
 
1024
1049
  if (logUploadSuccess) {
@@ -1048,10 +1073,11 @@ try {
1048
1073
  return `${days}:${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
1049
1074
  };
1050
1075
 
1051
- // Build Claude CLI resume command
1052
- const tool = argv.tool || 'claude';
1053
- const resumeCmd = tool === 'claude' ? buildClaudeResumeCommand({ tempDir, sessionId, model: argv.model }) : null;
1054
- const waitingComment = `ā³ **Usage Limit Reached - Waiting to Continue**\n\nThe AI tool has reached its usage limit. Auto-resume is enabled with \`--auto-resume-on-limit-reset\`.\n\n**Reset time:** ${global.limitResetTime}\n**Wait time:** ${formatWaitTime(waitMs)} (days:hours:minutes:seconds)\n\nThe session will automatically resume when the limit resets.\n\nSession ID: \`${sessionId}\`${resumeCmd ? `\n\nTo resume manually:\n\`\`\`bash\n${resumeCmd}\n\`\`\`` : ''}`;
1076
+ // For waiting comments, don't show CLI commands since auto-continue will handle it automatically
1077
+ // See: https://github.com/link-assistant/hive-mind/issues/1152
1078
+ const continueModeName = limitContinueMode === 'restart' ? 'auto-restart' : 'auto-resume';
1079
+ const continueDescription = limitContinueMode === 'restart' ? 'The session will automatically restart (fresh start) when the limit resets.' : 'The session will automatically resume (with context preserved) when the limit resets.';
1080
+ const waitingComment = `ā³ **Usage Limit Reached - Waiting to ${limitContinueMode === 'restart' ? 'Restart' : 'Continue'}**\n\nThe AI tool has reached its usage limit. ${continueModeName} is enabled.\n\n**Reset time:** ${global.limitResetTime}\n**Wait time:** ${formatWaitTime(waitMs)} (days:hours:minutes:seconds)\n\n${continueDescription}\n\nSession ID: \`${sessionId}\``;
1055
1081
 
1056
1082
  const commentResult = await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${waitingComment}`;
1057
1083
  if (commentResult.code === 0) {
@@ -1159,8 +1185,9 @@ try {
1159
1185
  // Pass shouldRestart to prevent early exit when auto-restart is needed
1160
1186
  // Include agent tool pricing data when available (publicPricingEstimate, pricingInfo)
1161
1187
  // Issue #1088: Pass errorDuringExecution for "Finished with errors" state
1188
+ // Issue #1152: Pass sessionType for differentiated log comments
1162
1189
  // Issue #1154: Track if logs were already uploaded to prevent duplicates
1163
- const verifyResult = await verifyResults(owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart, sessionId, tempDir, anthropicTotalCostUSD, publicPricingEstimate, pricingInfo, errorDuringExecution);
1190
+ const verifyResult = await verifyResults(owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart, sessionId, tempDir, anthropicTotalCostUSD, publicPricingEstimate, pricingInfo, errorDuringExecution, sessionType);
1164
1191
  const logsAlreadyUploaded = verifyResult?.logUploadSuccess || false;
1165
1192
 
1166
1193
  // Start watch mode if enabled OR if we need to handle uncommitted changes
@@ -416,7 +416,7 @@ export const showSessionSummary = async (sessionId, limitReached, argv, issueUrl
416
416
  };
417
417
 
418
418
  // Verify results by searching for new PRs and comments
419
- export const verifyResults = async (owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart = false, sessionId = null, tempDir = null, anthropicTotalCostUSD = null, publicPricingEstimate = null, pricingInfo = null, errorDuringExecution = false) => {
419
+ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumber, prUrl, referenceTime, argv, shouldAttachLogs, shouldRestart = false, sessionId = null, tempDir = null, anthropicTotalCostUSD = null, publicPricingEstimate = null, pricingInfo = null, errorDuringExecution = false, sessionType = 'new') => {
420
420
  await log('\nšŸ” Searching for created pull requests or comments...');
421
421
 
422
422
  try {
@@ -549,6 +549,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
549
549
  pricingInfo,
550
550
  // Issue #1088: Pass errorDuringExecution for "Finished with errors" state
551
551
  errorDuringExecution,
552
+ // Issue #1152: Pass sessionType for differentiated log comments
553
+ sessionType,
552
554
  });
553
555
  }
554
556
 
@@ -615,6 +617,8 @@ export const verifyResults = async (owner, repo, branchName, issueNumber, prNumb
615
617
  pricingInfo,
616
618
  // Issue #1088: Pass errorDuringExecution for "Finished with errors" state
617
619
  errorDuringExecution,
620
+ // Issue #1152: Pass sessionType for differentiated log comments
621
+ sessionType,
618
622
  });
619
623
  }
620
624
 
@@ -3,7 +3,67 @@
3
3
  * Handles starting and ending work sessions, PR status changes, and session comments
4
4
  */
5
5
 
6
- export async function startWorkSession({ isContinueMode, prNumber, argv, log, formatAligned, $ }) {
6
+ /**
7
+ * Session type definitions for different work session contexts
8
+ * See: https://github.com/link-assistant/hive-mind/issues/1152
9
+ */
10
+ export const SESSION_TYPES = {
11
+ NEW: 'new', // New work session (first time working on PR)
12
+ RESUME: 'resume', // Manual resume (--resume flag)
13
+ AUTO_RESUME: 'auto-resume', // Auto resume on limit reset (maintains context)
14
+ AUTO_RESTART: 'auto-restart', // Auto restart on limit reset (fresh start)
15
+ };
16
+
17
+ /**
18
+ * Get session comment header and description based on session type
19
+ * @param {string} sessionType - One of SESSION_TYPES values
20
+ * @param {Date} timestamp - Session start timestamp
21
+ * @returns {Object} - { emoji, header, description }
22
+ */
23
+ function getSessionCommentContent(sessionType, timestamp) {
24
+ const isoTime = timestamp.toISOString();
25
+
26
+ switch (sessionType) {
27
+ case SESSION_TYPES.RESUME:
28
+ return {
29
+ emoji: 'šŸ”„',
30
+ header: 'AI Work Session Resumed',
31
+ description: `Resuming automated work session at ${isoTime}\n\nThis session continues from a previous session using the \`--resume\` flag.\n\nThe PR has been converted to draft mode while work is in progress.\n\n_This comment marks the resumption of an AI work session. Please wait for the session to finish, and provide your feedback._`,
32
+ };
33
+ case SESSION_TYPES.AUTO_RESUME:
34
+ return {
35
+ emoji: 'ā°',
36
+ header: 'Auto Resume (on limit reset)',
37
+ description: `Auto-resuming automated work session at ${isoTime}\n\nThis session automatically resumed after the usage limit reset, continuing with the previous context preserved.\n\nThe PR has been converted to draft mode while work is in progress.\n\n_This is an auto-resumed session. Please wait for the session to finish, and provide your feedback._`,
38
+ };
39
+ case SESSION_TYPES.AUTO_RESTART:
40
+ return {
41
+ emoji: 'šŸ”„',
42
+ header: 'Auto Restart (on limit reset)',
43
+ description: `Auto-restarting automated work session at ${isoTime}\n\nThis session automatically restarted after the usage limit reset (fresh start without previous context).\n\nThe PR has been converted to draft mode while work is in progress.\n\n_This is a fresh restart after limit reset. Please wait for the session to finish, and provide your feedback._`,
44
+ };
45
+ case SESSION_TYPES.NEW:
46
+ default:
47
+ return {
48
+ emoji: 'šŸ¤–',
49
+ header: 'AI Work Session Started',
50
+ description: `Starting automated work session at ${isoTime}\n\nThe PR has been converted to draft mode while work is in progress.\n\n_This comment marks the beginning of an AI work session. Please wait for the session to finish, and provide your feedback._`,
51
+ };
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Start a work session and post appropriate comment
57
+ * @param {Object} options - Session options
58
+ * @param {boolean} options.isContinueMode - Whether this is a continue mode session
59
+ * @param {number} options.prNumber - PR number
60
+ * @param {Object} options.argv - Command line arguments
61
+ * @param {Function} options.log - Logging function
62
+ * @param {Function} options.formatAligned - Alignment formatting function
63
+ * @param {Function} options.$ - Command execution function
64
+ * @param {string} [options.sessionType='new'] - One of SESSION_TYPES values
65
+ */
66
+ export async function startWorkSession({ isContinueMode, prNumber, argv, log, formatAligned, $, sessionType = SESSION_TYPES.NEW }) {
7
67
  // Record work start time and convert PR to draft if in continue/watch mode
8
68
  const workStartTime = new Date();
9
69
  if (isContinueMode && prNumber && (argv.watch || argv.autoContinue)) {
@@ -37,12 +97,13 @@ export async function startWorkSession({ isContinueMode, prNumber, argv, log, fo
37
97
  await log('Warning: Could not check/convert PR draft status', { level: 'warning' });
38
98
  }
39
99
 
40
- // Post a comment marking the start of work session
100
+ // Post a comment marking the start of work session with appropriate header based on session type
41
101
  try {
42
- const startComment = `šŸ¤– **AI Work Session Started**\n\nStarting automated work session at ${workStartTime.toISOString()}\n\nThe PR has been converted to draft mode while work is in progress.\n\n_This comment marks the beginning of an AI work session. Please wait working session to finish, and provide your feedback._`;
102
+ const { emoji, header, description } = getSessionCommentContent(sessionType, workStartTime);
103
+ const startComment = `${emoji} **${header}**\n\n${description}`;
43
104
  const commentResult = await $`gh pr comment ${prNumber} --repo ${global.owner}/${global.repo} --body ${startComment}`;
44
105
  if (commentResult.code === 0) {
45
- await log(formatAligned('šŸ’¬', 'Posted:', 'Work session start comment', 2));
106
+ await log(formatAligned('šŸ’¬', 'Posted:', `${header} comment`, 2));
46
107
  }
47
108
  } catch (error) {
48
109
  const sentryLib = await import('./sentry.lib.mjs');
@@ -1102,7 +1102,7 @@ bot.command(/^solve$/i, async ctx => {
1102
1102
  return;
1103
1103
  }
1104
1104
 
1105
- const check = await solveQueue.canStartCommand();
1105
+ const check = await solveQueue.canStartCommand({ tool: solveTool }); // Skip Claude limits for agent (#1159)
1106
1106
  const queueStats = solveQueue.getStats();
1107
1107
  if (check.canStart && queueStats.queued === 0) {
1108
1108
  const startingMessage = await ctx.reply(`šŸš€ Starting solve command...\n\n${infoBlock}`, { parse_mode: 'Markdown', reply_to_message_id: ctx.message.message_id });