@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 +26 -0
- package/package.json +1 -1
- package/src/config.lib.mjs +8 -0
- package/src/github.lib.mjs +84 -25
- package/src/solve.auto-continue.lib.mjs +51 -15
- package/src/solve.config.lib.mjs +13 -1
- package/src/solve.mjs +39 -12
- package/src/solve.results.lib.mjs +5 -1
- package/src/solve.session.lib.mjs +65 -4
- package/src/telegram-bot.mjs +1 -1
- package/src/telegram-solve-queue.lib.mjs +364 -134
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
package/src/config.lib.mjs
CHANGED
|
@@ -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),
|
package/src/github.lib.mjs
CHANGED
|
@@ -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
|
-
|
|
461
|
-
|
|
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
|
-
|
|
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
|
-
|
|
467
|
-
|
|
486
|
+
if (resumeCommand) {
|
|
487
|
+
logComment += `you can resume this session by running:
|
|
468
488
|
\`\`\`bash
|
|
469
489
|
${resumeCommand}
|
|
470
490
|
\`\`\``;
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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
|
-
|
|
532
|
-
|
|
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
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
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
|
-
|
|
632
|
-
|
|
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
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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 ${
|
|
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
|
-
|
|
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
|
|
98
|
-
//
|
|
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
|
-
//
|
|
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
|
}
|
package/src/solve.config.lib.mjs
CHANGED
|
@@ -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 (
|
|
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-
|
|
916
|
-
if (!
|
|
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
|
-
|
|
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
|
-
//
|
|
1052
|
-
|
|
1053
|
-
const
|
|
1054
|
-
const
|
|
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
|
-
|
|
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
|
|
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:',
|
|
106
|
+
await log(formatAligned('š¬', 'Posted:', `${header} comment`, 2));
|
|
46
107
|
}
|
|
47
108
|
} catch (error) {
|
|
48
109
|
const sentryLib = await import('./sentry.lib.mjs');
|
package/src/telegram-bot.mjs
CHANGED
|
@@ -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 });
|