@link-assistant/hive-mind 0.51.6 → 0.51.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/src/claude-limits.lib.mjs +99 -5
- package/src/telegram-bot.mjs +5 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 0.51.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b7c7a2c: feat: add GitHub API rate limits to /limits command
|
|
8
|
+
|
|
9
|
+
Adds GitHub API core rate limit information to the Telegram bot's /limits command output, allowing users to monitor GitHub API usage alongside Claude usage limits and disk space. This helps plan issue execution when GitHub API limits are approaching.
|
|
10
|
+
|
|
3
11
|
## 0.51.6
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -147,6 +147,83 @@ function formatBytes(bytes) {
|
|
|
147
147
|
return `${value.toFixed(decimals)} ${sizes[i]}`;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Get GitHub API rate limits by calling gh api rate_limit
|
|
152
|
+
* Returns rate limit info for core, search, graphql, and other resources
|
|
153
|
+
*
|
|
154
|
+
* @param {boolean} verbose - Whether to log verbose output
|
|
155
|
+
* @returns {Object} Object with success boolean, and either rate limit data or error message
|
|
156
|
+
*/
|
|
157
|
+
export async function getGitHubRateLimits(verbose = false) {
|
|
158
|
+
try {
|
|
159
|
+
const { stdout } = await execAsync('gh api rate_limit 2>/dev/null');
|
|
160
|
+
const data = JSON.parse(stdout);
|
|
161
|
+
|
|
162
|
+
if (verbose) {
|
|
163
|
+
console.log('[VERBOSE] /limits GitHub rate limit response:', JSON.stringify(data, null, 2));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Extract the core rate limit (most important for general API usage)
|
|
167
|
+
const core = data.resources?.core;
|
|
168
|
+
if (!core) {
|
|
169
|
+
return {
|
|
170
|
+
success: false,
|
|
171
|
+
error: 'Could not parse GitHub rate limit response',
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Calculate remaining percentage
|
|
176
|
+
const usedPercentage = core.limit > 0 ? Math.round((core.used / core.limit) * 100) : 0;
|
|
177
|
+
const remainingPercentage = 100 - usedPercentage;
|
|
178
|
+
|
|
179
|
+
// Format reset time from Unix timestamp
|
|
180
|
+
const resetDate = new Date(core.reset * 1000);
|
|
181
|
+
const resetTimeFormatted = formatResetTime(resetDate.toISOString());
|
|
182
|
+
|
|
183
|
+
// Calculate relative time until reset
|
|
184
|
+
const now = new Date();
|
|
185
|
+
const diffMs = resetDate - now;
|
|
186
|
+
let relativeReset = null;
|
|
187
|
+
if (diffMs > 0) {
|
|
188
|
+
const totalMinutes = Math.floor(diffMs / (1000 * 60));
|
|
189
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
190
|
+
const minutes = totalMinutes % 60;
|
|
191
|
+
if (hours > 0) {
|
|
192
|
+
relativeReset = `${hours}h ${minutes}m`;
|
|
193
|
+
} else {
|
|
194
|
+
relativeReset = `${minutes}m`;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (verbose) {
|
|
199
|
+
console.log(`[VERBOSE] /limits GitHub API: ${core.remaining}/${core.limit} remaining (${remainingPercentage}% available)`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
success: true,
|
|
204
|
+
githubRateLimit: {
|
|
205
|
+
limit: core.limit,
|
|
206
|
+
used: core.used,
|
|
207
|
+
remaining: core.remaining,
|
|
208
|
+
usedPercentage,
|
|
209
|
+
remainingPercentage,
|
|
210
|
+
resetTimestamp: core.reset,
|
|
211
|
+
resetTime: resetTimeFormatted,
|
|
212
|
+
relativeReset,
|
|
213
|
+
resetsAt: resetDate.toISOString(),
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
} catch (error) {
|
|
217
|
+
if (verbose) {
|
|
218
|
+
console.error('[VERBOSE] /limits GitHub rate limit error:', error);
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
error: `Failed to get GitHub rate limits: ${error.message}`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
150
227
|
/**
|
|
151
228
|
* Get disk space information for the current filesystem
|
|
152
229
|
* Returns total, used, available space and usage percentage
|
|
@@ -385,9 +462,10 @@ export function calculateTimePassedPercentage(resetsAt, periodHours) {
|
|
|
385
462
|
* Format Claude usage data into a Telegram-friendly message
|
|
386
463
|
* @param {Object} usage - The usage object from getClaudeUsageLimits
|
|
387
464
|
* @param {Object} diskSpace - Optional disk space info from getDiskSpaceInfo
|
|
465
|
+
* @param {Object} githubRateLimit - Optional GitHub rate limit info from getGitHubRateLimits
|
|
388
466
|
* @returns {string} Formatted message
|
|
389
467
|
*/
|
|
390
|
-
export function formatUsageMessage(usage, diskSpace = null) {
|
|
468
|
+
export function formatUsageMessage(usage, diskSpace = null, githubRateLimit = null) {
|
|
391
469
|
// Use code block for monospace font to align progress bars properly
|
|
392
470
|
let message = '```\n';
|
|
393
471
|
|
|
@@ -397,10 +475,25 @@ export function formatUsageMessage(usage, diskSpace = null) {
|
|
|
397
475
|
// Disk space section (if provided)
|
|
398
476
|
if (diskSpace) {
|
|
399
477
|
message += 'Disk space\n';
|
|
400
|
-
// Show
|
|
401
|
-
const
|
|
402
|
-
message += `${
|
|
403
|
-
message += `${diskSpace.
|
|
478
|
+
// Show used percentage with progress bar
|
|
479
|
+
const usedBar = getProgressBar(diskSpace.usedPercentage);
|
|
480
|
+
message += `${usedBar} ${diskSpace.usedPercentage}% used\n`;
|
|
481
|
+
message += `${diskSpace.usedFormatted} used of ${diskSpace.totalFormatted}\n\n`;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// GitHub API rate limits section (if provided)
|
|
485
|
+
if (githubRateLimit) {
|
|
486
|
+
message += 'GitHub API\n';
|
|
487
|
+
// Show used percentage with progress bar
|
|
488
|
+
const usedBar = getProgressBar(githubRateLimit.usedPercentage);
|
|
489
|
+
message += `${usedBar} ${githubRateLimit.usedPercentage}% used\n`;
|
|
490
|
+
message += `${githubRateLimit.used}/${githubRateLimit.limit} requests used\n`;
|
|
491
|
+
if (githubRateLimit.relativeReset) {
|
|
492
|
+
message += `Resets in ${githubRateLimit.relativeReset} (${githubRateLimit.resetTime})\n`;
|
|
493
|
+
} else if (githubRateLimit.resetTime) {
|
|
494
|
+
message += `Resets ${githubRateLimit.resetTime}\n`;
|
|
495
|
+
}
|
|
496
|
+
message += '\n';
|
|
404
497
|
}
|
|
405
498
|
|
|
406
499
|
// Current session (five_hour)
|
|
@@ -493,6 +586,7 @@ export function formatUsageMessage(usage, diskSpace = null) {
|
|
|
493
586
|
export default {
|
|
494
587
|
getClaudeUsageLimits,
|
|
495
588
|
getDiskSpaceInfo,
|
|
589
|
+
getGitHubRateLimits,
|
|
496
590
|
getProgressBar,
|
|
497
591
|
calculateTimePassedPercentage,
|
|
498
592
|
formatUsageMessage,
|
package/src/telegram-bot.mjs
CHANGED
|
@@ -45,7 +45,7 @@ const { parseGitHubUrl } = await import('./github.lib.mjs');
|
|
|
45
45
|
const { validateModelName } = await import('./model-validation.lib.mjs');
|
|
46
46
|
|
|
47
47
|
// Import Claude limits library for /limits command
|
|
48
|
-
const { getClaudeUsageLimits, getDiskSpaceInfo, formatUsageMessage } = await import('./claude-limits.lib.mjs');
|
|
48
|
+
const { getClaudeUsageLimits, getDiskSpaceInfo, getGitHubRateLimits, formatUsageMessage } = await import('./claude-limits.lib.mjs');
|
|
49
49
|
|
|
50
50
|
// Import version info library for /version command
|
|
51
51
|
const { getVersionInfo, formatVersionMessage } = await import('./version-info.lib.mjs');
|
|
@@ -848,8 +848,8 @@ bot.command('limits', async ctx => {
|
|
|
848
848
|
reply_to_message_id: ctx.message.message_id,
|
|
849
849
|
});
|
|
850
850
|
|
|
851
|
-
// Get the usage limits
|
|
852
|
-
const [result, diskSpaceResult] = await Promise.all([getClaudeUsageLimits(VERBOSE), getDiskSpaceInfo(VERBOSE)]);
|
|
851
|
+
// Get the usage limits, disk space info, and GitHub rate limits in parallel
|
|
852
|
+
const [result, diskSpaceResult, githubLimitsResult] = await Promise.all([getClaudeUsageLimits(VERBOSE), getDiskSpaceInfo(VERBOSE), getGitHubRateLimits(VERBOSE)]);
|
|
853
853
|
|
|
854
854
|
if (!result.success) {
|
|
855
855
|
// Edit the fetching message to show the error
|
|
@@ -859,10 +859,8 @@ bot.command('limits', async ctx => {
|
|
|
859
859
|
return;
|
|
860
860
|
}
|
|
861
861
|
|
|
862
|
-
// Format and edit the fetching message with the results
|
|
863
|
-
|
|
864
|
-
const diskSpace = diskSpaceResult.success ? diskSpaceResult.diskSpace : null;
|
|
865
|
-
const message = '📊 *Usage Limits*\n\n' + formatUsageMessage(result.usage, diskSpace);
|
|
862
|
+
// Format and edit the fetching message with the results (pass disk space and GitHub limits if available)
|
|
863
|
+
const message = '📊 *Usage Limits*\n\n' + formatUsageMessage(result.usage, diskSpaceResult.success ? diskSpaceResult.diskSpace : null, githubLimitsResult.success ? githubLimitsResult.githubRateLimit : null);
|
|
866
864
|
await ctx.telegram.editMessageText(fetchingMessage.chat.id, fetchingMessage.message_id, undefined, message, {
|
|
867
865
|
parse_mode: 'Markdown',
|
|
868
866
|
});
|