@link-assistant/hive-mind 0.54.5 ā 1.0.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 +24 -0
- package/README.md +9 -8
- package/package.json +1 -1
- package/src/claude.command-builder.lib.mjs +2 -2
- package/src/hive.config.lib.mjs +2 -2
- package/src/hive.mjs +1 -1
- package/src/option-suggestions.lib.mjs +180 -0
- package/src/solve.auto-continue.lib.mjs +5 -4
- package/src/solve.config.lib.mjs +30 -6
- package/src/solve.mjs +18 -9
- package/src/solve.repository.lib.mjs +1 -1
- package/src/solve.results.lib.mjs +3 -3
- package/src/telegram-bot.mjs +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 4e8d141: Rename `--auto-continue-on-limit-reset` to `--auto-resume-on-limit-reset` for clarity
|
|
8
|
+
|
|
9
|
+
BREAKING CHANGE: The `--auto-continue-on-limit-reset` option has been renamed to `--auto-resume-on-limit-reset`. Users must update their commands and configurations to use the new flag name.
|
|
10
|
+
|
|
11
|
+
The option is related to `--resume` for `claude` command and has an entirely different meaning from `--auto-continue` mode. This rename makes the distinction clearer and aligns the terminology with the resume functionality.
|
|
12
|
+
|
|
13
|
+
Migration:
|
|
14
|
+
- Replace `--auto-continue-on-limit-reset` with `--auto-resume-on-limit-reset` in all commands
|
|
15
|
+
- Update environment variables and configuration files accordingly
|
|
16
|
+
|
|
17
|
+
## 0.54.6
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- f734d5d: feat: Add --base-branch to /help and implement option typo suggestions
|
|
22
|
+
- Added --base-branch option to Telegram bot /help command
|
|
23
|
+
- Implemented intelligent option name suggestions using Levenshtein distance
|
|
24
|
+
- Added --base-branch to README.md solve options section
|
|
25
|
+
- Enhanced error messages with helpful suggestions for typos (e.g., --branch ā --base-branch)
|
|
26
|
+
|
|
3
27
|
## 0.54.5
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -223,12 +223,12 @@ See [docs/HELM.md](./docs/HELM.md) for detailed Helm configuration options.
|
|
|
223
223
|
--attach-logs
|
|
224
224
|
--verbose
|
|
225
225
|
--no-tool-check
|
|
226
|
-
--auto-
|
|
226
|
+
--auto-resume-on-limit-reset
|
|
227
227
|
TELEGRAM_SOLVE_OVERRIDES:
|
|
228
228
|
--attach-logs
|
|
229
229
|
--verbose
|
|
230
230
|
--no-tool-check
|
|
231
|
-
--auto-
|
|
231
|
+
--auto-resume-on-limit-reset
|
|
232
232
|
TELEGRAM_BOT_VERBOSE: true
|
|
233
233
|
"
|
|
234
234
|
|
|
@@ -250,12 +250,12 @@ See [docs/HELM.md](./docs/HELM.md) for detailed Helm configuration options.
|
|
|
250
250
|
--attach-logs
|
|
251
251
|
--verbose
|
|
252
252
|
--no-tool-check
|
|
253
|
-
--auto-
|
|
253
|
+
--auto-resume-on-limit-reset
|
|
254
254
|
)" --solve-overrides "(
|
|
255
255
|
--attach-logs
|
|
256
256
|
--verbose
|
|
257
257
|
--no-tool-check
|
|
258
|
-
--auto-
|
|
258
|
+
--auto-resume-on-limit-reset
|
|
259
259
|
)" --verbose
|
|
260
260
|
|
|
261
261
|
# Press CTRL + A + D for detach from screen
|
|
@@ -332,10 +332,11 @@ solve <issue-url> [options]
|
|
|
332
332
|
|
|
333
333
|
**Most frequently used options:**
|
|
334
334
|
|
|
335
|
-
| Option
|
|
336
|
-
|
|
|
337
|
-
| `--model`
|
|
338
|
-
| `--think`
|
|
335
|
+
| Option | Alias | Description | Default |
|
|
336
|
+
| --------------- | ----- | --------------------------------------- | --------- |
|
|
337
|
+
| `--model` | `-m` | AI model to use (sonnet, opus, haiku) | sonnet |
|
|
338
|
+
| `--think` | | Thinking level (low, medium, high, max) | - |
|
|
339
|
+
| `--base-branch` | `-b` | Target branch for PR | (default) |
|
|
339
340
|
|
|
340
341
|
**Other useful options:**
|
|
341
342
|
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* (cd "/path/to/workdir" && claude --resume <session-id>)
|
|
11
11
|
*
|
|
12
|
-
* This is the same pattern used by --auto-
|
|
12
|
+
* This is the same pattern used by --auto-resume-on-limit-reset and allows users to:
|
|
13
13
|
* 1. Resume sessions directly using Claude CLI (not through solve.mjs)
|
|
14
14
|
* 2. Investigate issues interactively in the working directory
|
|
15
15
|
* 3. Continue work after usage limits reset
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*
|
|
27
27
|
* This generates a copy-pasteable command that users can execute directly
|
|
28
28
|
* to resume a Claude session in interactive mode. This is the same pattern
|
|
29
|
-
* used by --auto-
|
|
29
|
+
* used by --auto-resume-on-limit-reset.
|
|
30
30
|
*
|
|
31
31
|
* The command includes all necessary flags to match how the original session was run:
|
|
32
32
|
* - --resume <sessionId>: Resume from the specified session
|
package/src/hive.config.lib.mjs
CHANGED
|
@@ -202,9 +202,9 @@ export const createYargsConfig = yargsInstance => {
|
|
|
202
202
|
description: 'Pass --auto-continue to solve for each issue (continues with existing PRs instead of creating new ones)',
|
|
203
203
|
default: true,
|
|
204
204
|
})
|
|
205
|
-
.option('auto-
|
|
205
|
+
.option('auto-resume-on-limit-reset', {
|
|
206
206
|
type: 'boolean',
|
|
207
|
-
description: 'Automatically
|
|
207
|
+
description: 'Automatically resume when AI tool limit resets (calculates reset time and waits). Passed to solve command.',
|
|
208
208
|
default: false,
|
|
209
209
|
})
|
|
210
210
|
.option('think', {
|
package/src/hive.mjs
CHANGED
|
@@ -745,7 +745,7 @@ if (isDirectExecution) {
|
|
|
745
745
|
if (argv.dryRun) args.push('--dry-run');
|
|
746
746
|
if (argv.skipToolConnectionCheck || argv.toolConnectionCheck === false) args.push('--skip-tool-connection-check');
|
|
747
747
|
args.push(argv.autoContinue ? '--auto-continue' : '--no-auto-continue');
|
|
748
|
-
if (argv.
|
|
748
|
+
if (argv.autoResumeOnLimitReset) args.push('--auto-resume-on-limit-reset');
|
|
749
749
|
if (argv.think) args.push('--think', argv.think);
|
|
750
750
|
if (argv.promptPlanSubAgent) args.push('--prompt-plan-sub-agent');
|
|
751
751
|
if (!argv.sentry) args.push('--no-sentry');
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// Option suggestion utility for providing helpful error messages
|
|
2
|
+
// when users mistype command-line option names
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Calculate Levenshtein distance between two strings
|
|
6
|
+
* Measures the minimum number of single-character edits (insertions, deletions, or substitutions)
|
|
7
|
+
* required to change one string into the other.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} a - First string
|
|
10
|
+
* @param {string} b - Second string
|
|
11
|
+
* @returns {number} - Levenshtein distance
|
|
12
|
+
*/
|
|
13
|
+
export function calculateLevenshteinDistance(a, b) {
|
|
14
|
+
if (a.length === 0) return b.length;
|
|
15
|
+
if (b.length === 0) return a.length;
|
|
16
|
+
|
|
17
|
+
const matrix = [];
|
|
18
|
+
|
|
19
|
+
// Initialize first column of matrix
|
|
20
|
+
for (let i = 0; i <= b.length; i++) {
|
|
21
|
+
matrix[i] = [i];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Initialize first row of matrix
|
|
25
|
+
for (let j = 0; j <= a.length; j++) {
|
|
26
|
+
matrix[0][j] = j;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Fill in the rest of the matrix
|
|
30
|
+
for (let i = 1; i <= b.length; i++) {
|
|
31
|
+
for (let j = 1; j <= a.length; j++) {
|
|
32
|
+
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
33
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
34
|
+
} else {
|
|
35
|
+
matrix[i][j] = Math.min(
|
|
36
|
+
matrix[i - 1][j - 1] + 1, // substitution
|
|
37
|
+
matrix[i][j - 1] + 1, // insertion
|
|
38
|
+
matrix[i - 1][j] + 1 // deletion
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return matrix[b.length][a.length];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Find similar option names based on Levenshtein distance
|
|
49
|
+
*
|
|
50
|
+
* @param {string} unknownOption - The option name that was not recognized (e.g., "branch")
|
|
51
|
+
* @param {Object} yargsInstance - The yargs instance with defined options
|
|
52
|
+
* @param {number} maxSuggestions - Maximum number of suggestions to return (default: 3)
|
|
53
|
+
* @param {number} distanceThreshold - Maximum distance to consider for suggestions (default: 5)
|
|
54
|
+
* @returns {string[]} - Array of suggested option names, sorted by similarity
|
|
55
|
+
*/
|
|
56
|
+
export function findSimilarOptions(unknownOption, yargsInstance, maxSuggestions = 3, distanceThreshold = 5) {
|
|
57
|
+
// Remove leading dashes from the unknown option
|
|
58
|
+
const cleanUnknown = unknownOption.replace(/^-+/, '');
|
|
59
|
+
|
|
60
|
+
// Get all available options from yargs
|
|
61
|
+
const availableOptions = yargsInstance.getOptions();
|
|
62
|
+
const allOptions = new Set();
|
|
63
|
+
|
|
64
|
+
// Collect all option names (both long form and aliases)
|
|
65
|
+
if (availableOptions.key) {
|
|
66
|
+
// Ensure it's an array before iterating
|
|
67
|
+
const keys = Array.isArray(availableOptions.key) ? availableOptions.key : Object.keys(availableOptions.key || {});
|
|
68
|
+
keys.forEach(opt => {
|
|
69
|
+
allOptions.add(opt);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Collect aliases
|
|
74
|
+
if (availableOptions.alias) {
|
|
75
|
+
Object.entries(availableOptions.alias).forEach(([key, aliases]) => {
|
|
76
|
+
allOptions.add(key);
|
|
77
|
+
if (Array.isArray(aliases)) {
|
|
78
|
+
aliases.forEach(alias => allOptions.add(alias));
|
|
79
|
+
} else if (aliases) {
|
|
80
|
+
// If it's not an array but exists, add it as a single alias
|
|
81
|
+
allOptions.add(String(aliases));
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Calculate distance for each option
|
|
87
|
+
const distances = [];
|
|
88
|
+
allOptions.forEach(option => {
|
|
89
|
+
const distance = calculateLevenshteinDistance(cleanUnknown, option);
|
|
90
|
+
if (distance <= distanceThreshold) {
|
|
91
|
+
// Calculate bonus score for substring matches
|
|
92
|
+
// If the unknown option is a substring of the valid option, it's likely what the user meant
|
|
93
|
+
// Check both directions: is unknown a substring of option, or is option a substring of unknown
|
|
94
|
+
const unknownInOption = option.includes(cleanUnknown);
|
|
95
|
+
const optionInUnknown = cleanUnknown.includes(option);
|
|
96
|
+
|
|
97
|
+
// Strong bonus for when user typed a word that appears in the option name
|
|
98
|
+
// e.g., "branch" appears in "base-branch"
|
|
99
|
+
const substringBonus = unknownInOption ? -10 : optionInUnknown ? -5 : 0;
|
|
100
|
+
|
|
101
|
+
// Also prioritize options with similar length (user likely tried to type the full name)
|
|
102
|
+
const lengthDiff = Math.abs(option.length - cleanUnknown.length);
|
|
103
|
+
const lengthBonus = lengthDiff < 3 ? -1 : 0;
|
|
104
|
+
|
|
105
|
+
distances.push({
|
|
106
|
+
option,
|
|
107
|
+
distance,
|
|
108
|
+
effectiveDistance: distance + substringBonus + lengthBonus,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Sort by effective distance (closest first), then by actual distance
|
|
114
|
+
return distances
|
|
115
|
+
.sort((a, b) => {
|
|
116
|
+
if (a.effectiveDistance !== b.effectiveDistance) {
|
|
117
|
+
return a.effectiveDistance - b.effectiveDistance;
|
|
118
|
+
}
|
|
119
|
+
return a.distance - b.distance;
|
|
120
|
+
})
|
|
121
|
+
.slice(0, maxSuggestions)
|
|
122
|
+
.map(item => item.option);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Format suggestions into a user-friendly error message
|
|
127
|
+
*
|
|
128
|
+
* @param {string[]} suggestions - Array of suggested option names
|
|
129
|
+
* @returns {string} - Formatted suggestion message
|
|
130
|
+
*/
|
|
131
|
+
export function formatSuggestions(suggestions) {
|
|
132
|
+
if (suggestions.length === 0) {
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (suggestions.length === 1) {
|
|
137
|
+
return `\n\nDid you mean --${suggestions[0]}?`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// For multiple suggestions, format them nicely
|
|
141
|
+
const formattedOptions = suggestions.map(opt => {
|
|
142
|
+
// If it's a single character, show as -x, otherwise --option-name
|
|
143
|
+
return opt.length === 1 ? `-${opt}` : `--${opt}`;
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
return `\n\nDid you mean one of these?\n${formattedOptions.map(opt => ` ⢠${opt}`).join('\n')}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Create an enhanced error message with suggestions for unknown arguments
|
|
151
|
+
*
|
|
152
|
+
* @param {string} originalError - The original error message from yargs
|
|
153
|
+
* @param {Object} yargsInstance - The yargs instance with defined options
|
|
154
|
+
* @returns {string} - Enhanced error message with suggestions
|
|
155
|
+
*/
|
|
156
|
+
export function enhanceErrorMessage(originalError, yargsInstance) {
|
|
157
|
+
// Extract the unknown option name from the error message
|
|
158
|
+
// Typical format: "Unknown argument: branch" or "Unknown arguments: branch, test"
|
|
159
|
+
const unknownMatch = originalError.match(/Unknown arguments?:\s*(.+?)(?:\s|$)/i);
|
|
160
|
+
|
|
161
|
+
if (!unknownMatch) {
|
|
162
|
+
return originalError;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Get the first unknown argument (if multiple, focus on the first)
|
|
166
|
+
const unknownArgs = unknownMatch[1].split(',').map(arg => arg.trim());
|
|
167
|
+
const firstUnknown = unknownArgs[0];
|
|
168
|
+
|
|
169
|
+
// Find similar options
|
|
170
|
+
const suggestions = findSimilarOptions(firstUnknown, yargsInstance);
|
|
171
|
+
|
|
172
|
+
// Format the enhanced message
|
|
173
|
+
let enhancedMessage = originalError;
|
|
174
|
+
|
|
175
|
+
if (suggestions.length > 0) {
|
|
176
|
+
enhancedMessage += formatSuggestions(suggestions);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return enhancedMessage;
|
|
180
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// Session continuation module for solve command
|
|
4
|
+
// Handles session resumption, PR detection, and limit reset waiting
|
|
4
5
|
// Extracted from solve.mjs to keep files under 1500 lines
|
|
5
6
|
|
|
6
7
|
// Use use-m to dynamically import modules for cross-runtime compatibility
|
|
@@ -103,9 +104,9 @@ export const autoContinueWhenLimitResets = async (issueUrl, sessionId, argv, sho
|
|
|
103
104
|
sessionId,
|
|
104
105
|
];
|
|
105
106
|
|
|
106
|
-
// Preserve auto-
|
|
107
|
-
if (argv.
|
|
108
|
-
resumeArgs.push('--auto-
|
|
107
|
+
// Preserve auto-resume flag
|
|
108
|
+
if (argv.autoResumeOnLimitReset) {
|
|
109
|
+
resumeArgs.push('--auto-resume-on-limit-reset');
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
// Preserve other flags from original invocation
|
package/src/solve.config.lib.mjs
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
// Note: Strict options validation is now handled by yargs built-in .strict() mode (see below)
|
|
8
8
|
// This approach was adopted per issue #482 feedback to minimize custom code maintenance
|
|
9
9
|
|
|
10
|
+
import { enhanceErrorMessage } from './option-suggestions.lib.mjs';
|
|
11
|
+
|
|
10
12
|
// Export an initialization function that accepts 'use'
|
|
11
13
|
export const initializeConfig = async use => {
|
|
12
14
|
// Import yargs with specific version for hideBin support
|
|
@@ -143,9 +145,9 @@ export const createYargsConfig = yargsInstance => {
|
|
|
143
145
|
description: 'Continue with existing PR when issue URL is provided (instead of creating new PR)',
|
|
144
146
|
default: true,
|
|
145
147
|
})
|
|
146
|
-
.option('auto-
|
|
148
|
+
.option('auto-resume-on-limit-reset', {
|
|
147
149
|
type: 'boolean',
|
|
148
|
-
description: 'Automatically
|
|
150
|
+
description: 'Automatically resume when AI tool limit resets (calculates reset time and waits)',
|
|
149
151
|
default: false,
|
|
150
152
|
})
|
|
151
153
|
.option('auto-resume-on-errors', {
|
|
@@ -310,6 +312,7 @@ export const parseArguments = async (yargs, hideBin) => {
|
|
|
310
312
|
// See: https://github.com/yargs/yargs/issues - .strict() only works with .parse()
|
|
311
313
|
|
|
312
314
|
let argv;
|
|
315
|
+
let yargsInstance;
|
|
313
316
|
try {
|
|
314
317
|
// Suppress stderr output from yargs during parsing to prevent validation errors from appearing
|
|
315
318
|
// This prevents "YError: Not enough arguments" from polluting stderr (issue #583)
|
|
@@ -330,7 +333,8 @@ export const parseArguments = async (yargs, hideBin) => {
|
|
|
330
333
|
};
|
|
331
334
|
|
|
332
335
|
try {
|
|
333
|
-
|
|
336
|
+
yargsInstance = createYargsConfig(yargs());
|
|
337
|
+
argv = await yargsInstance.parse(rawArgs);
|
|
334
338
|
} finally {
|
|
335
339
|
// Always restore stderr.write
|
|
336
340
|
process.stderr.write = originalStderrWrite;
|
|
@@ -345,9 +349,29 @@ export const parseArguments = async (yargs, hideBin) => {
|
|
|
345
349
|
}
|
|
346
350
|
} catch (error) {
|
|
347
351
|
// Yargs throws errors for validation issues
|
|
348
|
-
// If the error is about unknown arguments (strict mode),
|
|
349
|
-
if
|
|
350
|
-
|
|
352
|
+
// If the error is about unknown arguments (strict mode), enhance it with suggestions
|
|
353
|
+
// Check if this error has already been enhanced to avoid re-processing
|
|
354
|
+
if (error.message && /Unknown argument/.test(error.message) && !error._enhanced) {
|
|
355
|
+
try {
|
|
356
|
+
// Enhance the error message with helpful suggestions
|
|
357
|
+
// Use the yargsInstance we already created, or create a new one if needed
|
|
358
|
+
const yargsWithConfig = yargsInstance || createYargsConfig(yargs());
|
|
359
|
+
const enhancedMessage = enhanceErrorMessage(error.message, yargsWithConfig);
|
|
360
|
+
const enhancedError = new Error(enhancedMessage);
|
|
361
|
+
enhancedError.name = error.name;
|
|
362
|
+
enhancedError._enhanced = true; // Mark as enhanced to prevent re-processing
|
|
363
|
+
throw enhancedError;
|
|
364
|
+
} catch (enhanceErr) {
|
|
365
|
+
// If enhancing fails, just throw the original error
|
|
366
|
+
if (global.verboseMode) {
|
|
367
|
+
console.error('[VERBOSE] Failed to enhance error message:', enhanceErr.message);
|
|
368
|
+
}
|
|
369
|
+
// If the enhance error itself is already enhanced, throw it
|
|
370
|
+
if (enhanceErr._enhanced) {
|
|
371
|
+
throw enhanceErr;
|
|
372
|
+
}
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
351
375
|
}
|
|
352
376
|
// For other validation errors, show a warning in verbose mode
|
|
353
377
|
if (error.message && global.verboseMode) {
|
package/src/solve.mjs
CHANGED
|
@@ -104,7 +104,16 @@ await log('š§ Raw command executed:');
|
|
|
104
104
|
await log(` ${rawCommand}`);
|
|
105
105
|
await log('');
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
let argv;
|
|
108
|
+
try {
|
|
109
|
+
argv = await parseArguments(yargs, hideBin);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
// Handle argument parsing errors with helpful messages
|
|
112
|
+
await log(`ā ${error.message}`, { level: 'error' });
|
|
113
|
+
await log('', { level: 'error' });
|
|
114
|
+
await log('Use /help to see available options', { level: 'error' });
|
|
115
|
+
await safeExit(1, 'Invalid command-line arguments');
|
|
116
|
+
}
|
|
108
117
|
global.verboseMode = argv.verbose;
|
|
109
118
|
|
|
110
119
|
// If user specified a custom log directory, we would need to move the log file
|
|
@@ -883,10 +892,10 @@ try {
|
|
|
883
892
|
|
|
884
893
|
// Handle limit reached scenario
|
|
885
894
|
if (limitReached) {
|
|
886
|
-
const
|
|
895
|
+
const shouldAutoResumeOnReset = argv.autoResumeOnLimitReset;
|
|
887
896
|
|
|
888
|
-
// If limit was reached but auto-
|
|
889
|
-
if (!
|
|
897
|
+
// If limit was reached but auto-resume-on-limit-reset is NOT enabled, fail immediately
|
|
898
|
+
if (!shouldAutoResumeOnReset) {
|
|
890
899
|
await log('\nā USAGE LIMIT REACHED!');
|
|
891
900
|
await log(' The AI tool has reached its usage limit.');
|
|
892
901
|
|
|
@@ -963,9 +972,9 @@ try {
|
|
|
963
972
|
}
|
|
964
973
|
}
|
|
965
974
|
|
|
966
|
-
await safeExit(1, 'Usage limit reached - use --auto-
|
|
975
|
+
await safeExit(1, 'Usage limit reached - use --auto-resume-on-limit-reset to wait for reset');
|
|
967
976
|
} else {
|
|
968
|
-
// auto-
|
|
977
|
+
// auto-resume-on-limit-reset is enabled - attach logs and/or post waiting comment
|
|
969
978
|
if (prNumber && global.limitResetTime) {
|
|
970
979
|
// If --attach-logs is enabled, upload logs with usage limit details
|
|
971
980
|
if (shouldAttachLogs && sessionId) {
|
|
@@ -1021,7 +1030,7 @@ try {
|
|
|
1021
1030
|
// Build Claude CLI resume command
|
|
1022
1031
|
const tool = argv.tool || 'claude';
|
|
1023
1032
|
const resumeCmd = tool === 'claude' ? buildClaudeResumeCommand({ tempDir, sessionId, model: argv.model }) : null;
|
|
1024
|
-
const waitingComment = `ā³ **Usage Limit Reached - Waiting to Continue**\n\nThe AI tool has reached its usage limit. Auto-
|
|
1033
|
+
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\`\`\`` : ''}`;
|
|
1025
1034
|
|
|
1026
1035
|
const commentResult = await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${waitingComment}`;
|
|
1027
1036
|
if (commentResult.code === 0) {
|
|
@@ -1035,9 +1044,9 @@ try {
|
|
|
1035
1044
|
}
|
|
1036
1045
|
}
|
|
1037
1046
|
|
|
1038
|
-
// Handle failure cases, but skip exit if limit reached with auto-
|
|
1047
|
+
// Handle failure cases, but skip exit if limit reached with auto-resume enabled
|
|
1039
1048
|
// This allows the code to continue to showSessionSummary() where autoContinueWhenLimitResets() is called
|
|
1040
|
-
const shouldSkipFailureExitForAutoLimitContinue = limitReached && argv.
|
|
1049
|
+
const shouldSkipFailureExitForAutoLimitContinue = limitReached && argv.autoResumeOnLimitReset;
|
|
1041
1050
|
|
|
1042
1051
|
if (!success && !shouldSkipFailureExitForAutoLimitContinue) {
|
|
1043
1052
|
// Show claude resume command only for --tool claude (or default) on failure
|
|
@@ -1171,7 +1171,7 @@ export const checkoutPrBranch = async (tempDir, branchName, prForkRemote, prFork
|
|
|
1171
1171
|
// Cleanup temporary directory
|
|
1172
1172
|
export const cleanupTempDirectory = async (tempDir, argv, limitReached) => {
|
|
1173
1173
|
// Determine if we should skip cleanup
|
|
1174
|
-
const shouldKeepDirectory = !argv.autoCleanup || argv.resume || limitReached || (argv.
|
|
1174
|
+
const shouldKeepDirectory = !argv.autoCleanup || argv.resume || limitReached || (argv.autoResumeOnLimitReset && global.limitResetTime);
|
|
1175
1175
|
|
|
1176
1176
|
if (!shouldKeepDirectory) {
|
|
1177
1177
|
try {
|
|
@@ -27,7 +27,7 @@ import { safeExit } from './exit-handler.lib.mjs';
|
|
|
27
27
|
const githubLib = await import('./github.lib.mjs');
|
|
28
28
|
const { sanitizeLogContent, attachLogToGitHub } = githubLib;
|
|
29
29
|
|
|
30
|
-
// Import
|
|
30
|
+
// Import continuation functions (session resumption, PR detection)
|
|
31
31
|
const autoContinue = await import('./solve.auto-continue.lib.mjs');
|
|
32
32
|
const { autoContinueWhenLimitResets } = autoContinue;
|
|
33
33
|
|
|
@@ -376,8 +376,8 @@ export const showSessionSummary = async (sessionId, limitReached, argv, issueUrl
|
|
|
376
376
|
if (limitReached) {
|
|
377
377
|
await log('ā° LIMIT REACHED DETECTED!');
|
|
378
378
|
|
|
379
|
-
if (argv.
|
|
380
|
-
await log(`\nš AUTO-
|
|
379
|
+
if (argv.autoResumeOnLimitReset && global.limitResetTime) {
|
|
380
|
+
await log(`\nš AUTO-RESUME ON LIMIT RESET ENABLED - Will resume at ${global.limitResetTime}`);
|
|
381
381
|
await autoContinueWhenLimitResets(issueUrl, sessionId, argv, shouldAttachLogs);
|
|
382
382
|
} else {
|
|
383
383
|
if (global.limitResetTime) {
|
package/src/telegram-bot.mjs
CHANGED
|
@@ -807,11 +807,12 @@ bot.command('help', async ctx => {
|
|
|
807
807
|
message += '*/version* - Show bot and runtime versions\n';
|
|
808
808
|
message += '*/help* - Show this help message\n\n';
|
|
809
809
|
message += 'ā ļø *Note:* /solve, /hive, /limits and /version commands only work in group chats.\n\n';
|
|
810
|
-
message += 'š§ *
|
|
811
|
-
message += '⢠`--model <model>` - Specify AI model (sonnet, opus, haiku, haiku-3-5, haiku-3)\n';
|
|
810
|
+
message += 'š§ *Common Options:*\n';
|
|
811
|
+
message += '⢠`--model <model>` or `-m` - Specify AI model (sonnet, opus, haiku, haiku-3-5, haiku-3)\n';
|
|
812
|
+
message += '⢠`--base-branch <branch>` or `-b` - Target branch for PR (default: repo default branch)\n';
|
|
812
813
|
message += '⢠`--think <level>` - Thinking level (low/medium/high/max)\n';
|
|
813
|
-
message += '⢠`--verbose` - Verbose output\n';
|
|
814
|
-
message += '
|
|
814
|
+
message += '⢠`--verbose` or `-v` - Verbose output | `--attach-logs` - Attach logs to PR\n';
|
|
815
|
+
message += '\nš” *Tip:* Many more options available. See full documentation for complete list.\n';
|
|
815
816
|
|
|
816
817
|
if (allowedChats) {
|
|
817
818
|
message += '\nš *Restricted Mode:* This bot only accepts commands from authorized chats.\n';
|