@link-assistant/hive-mind 1.9.1 → 1.10.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 +27 -0
- package/package.json +1 -1
- package/src/claude.lib.mjs +4 -1
- package/src/config.lib.mjs +20 -1
- package/src/telegram-solve-queue.lib.mjs +33 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9b56b26: feat(solve): configure MCP_TIMEOUT and MCP_TOOL_TIMEOUT for claude tool calls
|
|
8
|
+
|
|
9
|
+
Added MCP timeout configuration to prevent tool calls from hanging indefinitely:
|
|
10
|
+
- Added `mcpTimeout` config (default: 900000ms / 15 minutes) for MCP server startup
|
|
11
|
+
- Added `mcpToolTimeout` config (default: 900000ms / 15 minutes) for MCP tool execution
|
|
12
|
+
- Support for override via `MCP_TIMEOUT`/`HIVE_MIND_MCP_TIMEOUT` and `MCP_TOOL_TIMEOUT`/`HIVE_MIND_MCP_TOOL_TIMEOUT` environment variables
|
|
13
|
+
- Updated `getClaudeEnv()` to pass both timeout values to Claude CLI
|
|
14
|
+
- Added verbose logging for MCP timeout values
|
|
15
|
+
|
|
16
|
+
Fixes #1066
|
|
17
|
+
|
|
18
|
+
## 1.9.2
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- d39bf3e: Fix disk threshold to use one-at-a-time mode instead of blocking all commands
|
|
23
|
+
- When disk usage exceeds threshold (90%), now allows exactly one command to run
|
|
24
|
+
- Previously, disk threshold blocked ALL commands unconditionally (like RAM/CPU)
|
|
25
|
+
- Now matches behavior of Claude API thresholds (CLAUDE_5_HOUR_SESSION_THRESHOLD, CLAUDE_WEEKLY_THRESHOLD)
|
|
26
|
+
- Allows controlled task execution during high disk usage while preventing multiple tasks from exhausting resources
|
|
27
|
+
|
|
28
|
+
Fixes #1155
|
|
29
|
+
|
|
3
30
|
## 1.9.1
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/package.json
CHANGED
package/src/claude.lib.mjs
CHANGED
|
@@ -881,9 +881,12 @@ export const executeClaudeCommand = async params => {
|
|
|
881
881
|
// See issue #1146 for details on thinking budget translation
|
|
882
882
|
const { thinkingBudget: resolvedThinkingBudget, thinkLevel, isNewVersion } = await resolveThinkingSettings(argv, log);
|
|
883
883
|
|
|
884
|
-
// Set CLAUDE_CODE_MAX_OUTPUT_TOKENS (see issue #1076)
|
|
884
|
+
// Set CLAUDE_CODE_MAX_OUTPUT_TOKENS (see issue #1076), MAX_THINKING_TOKENS (see issue #1146),
|
|
885
|
+
// and MCP timeout configurations (see issue #1066)
|
|
885
886
|
const claudeEnv = getClaudeEnv({ thinkingBudget: resolvedThinkingBudget });
|
|
886
887
|
if (argv.verbose) await log(`📊 CLAUDE_CODE_MAX_OUTPUT_TOKENS: ${claudeCode.maxOutputTokens}`, { verbose: true });
|
|
888
|
+
if (argv.verbose) await log(`📊 MCP_TIMEOUT: ${claudeCode.mcpTimeout}ms (server startup)`, { verbose: true });
|
|
889
|
+
if (argv.verbose) await log(`📊 MCP_TOOL_TIMEOUT: ${claudeCode.mcpToolTimeout}ms (tool execution)`, { verbose: true });
|
|
887
890
|
if (resolvedThinkingBudget !== undefined) {
|
|
888
891
|
await log(`📊 MAX_THINKING_TOKENS: ${resolvedThinkingBudget}`, { verbose: true });
|
|
889
892
|
}
|
package/src/config.lib.mjs
CHANGED
|
@@ -90,6 +90,15 @@ export const claudeCode = {
|
|
|
90
90
|
// Default: 64000 (matches Claude Sonnet/Opus/Haiku 4.5 model capabilities)
|
|
91
91
|
// Set via CLAUDE_CODE_MAX_OUTPUT_TOKENS or HIVE_MIND_CLAUDE_CODE_MAX_OUTPUT_TOKENS
|
|
92
92
|
maxOutputTokens: parseIntWithDefault('CLAUDE_CODE_MAX_OUTPUT_TOKENS', parseIntWithDefault('HIVE_MIND_CLAUDE_CODE_MAX_OUTPUT_TOKENS', 64000)),
|
|
93
|
+
// MCP (Model Context Protocol) timeout configurations
|
|
94
|
+
// See: https://github.com/link-assistant/hive-mind/issues/1066
|
|
95
|
+
// See: https://code.claude.com/docs/en/settings#environment-variables
|
|
96
|
+
// MCP_TIMEOUT: Timeout in milliseconds for MCP server startup
|
|
97
|
+
// MCP_TOOL_TIMEOUT: Timeout in milliseconds for MCP tool execution
|
|
98
|
+
// Default: 900000ms (15 minutes) to accommodate long-running Playwright operations
|
|
99
|
+
// Set via MCP_TIMEOUT/MCP_TOOL_TIMEOUT or HIVE_MIND_MCP_TIMEOUT/HIVE_MIND_MCP_TOOL_TIMEOUT
|
|
100
|
+
mcpTimeout: parseIntWithDefault('MCP_TIMEOUT', parseIntWithDefault('HIVE_MIND_MCP_TIMEOUT', 900000)),
|
|
101
|
+
mcpToolTimeout: parseIntWithDefault('MCP_TOOL_TIMEOUT', parseIntWithDefault('HIVE_MIND_MCP_TOOL_TIMEOUT', 900000)),
|
|
93
102
|
};
|
|
94
103
|
|
|
95
104
|
// Default max thinking budget for Claude Code (see issue #1146)
|
|
@@ -156,8 +165,18 @@ export const supportsThinkingBudget = (version, minVersion = '2.1.12') => {
|
|
|
156
165
|
|
|
157
166
|
// Helper function to get Claude CLI environment with CLAUDE_CODE_MAX_OUTPUT_TOKENS set
|
|
158
167
|
// Optionally sets MAX_THINKING_TOKENS when thinkingBudget is provided (see issue #1146)
|
|
168
|
+
// Also sets MCP_TIMEOUT and MCP_TOOL_TIMEOUT for MCP tool execution (see issue #1066)
|
|
159
169
|
export const getClaudeEnv = (options = {}) => {
|
|
160
|
-
const env = {
|
|
170
|
+
const env = {
|
|
171
|
+
...process.env,
|
|
172
|
+
CLAUDE_CODE_MAX_OUTPUT_TOKENS: String(claudeCode.maxOutputTokens),
|
|
173
|
+
// MCP timeout configurations to prevent tool calls from hanging indefinitely
|
|
174
|
+
// See: https://github.com/link-assistant/hive-mind/issues/1066
|
|
175
|
+
// MCP_TIMEOUT: Timeout for MCP server startup
|
|
176
|
+
// MCP_TOOL_TIMEOUT: Timeout for MCP tool execution (the one that prevents stuck tools)
|
|
177
|
+
MCP_TIMEOUT: String(claudeCode.mcpTimeout),
|
|
178
|
+
MCP_TOOL_TIMEOUT: String(claudeCode.mcpToolTimeout),
|
|
179
|
+
};
|
|
161
180
|
// Set MAX_THINKING_TOKENS if thinkingBudget is provided
|
|
162
181
|
// This controls Claude Code's extended thinking feature (Claude Code >= 2.1.12)
|
|
163
182
|
// Default is 31999, set to 0 to disable thinking, max is 63999 for 64K output models
|
|
@@ -34,16 +34,16 @@ import { getCachedClaudeLimits, getCachedGitHubLimits, getCachedMemoryInfo, getC
|
|
|
34
34
|
export const QUEUE_CONFIG = {
|
|
35
35
|
// Resource thresholds (usage ratios: 0.0 - 1.0)
|
|
36
36
|
// All thresholds use >= comparison (inclusive)
|
|
37
|
-
RAM_THRESHOLD: 0.65, //
|
|
37
|
+
RAM_THRESHOLD: 0.65, // Enqueue if RAM usage >= 65%
|
|
38
38
|
// CPU threshold uses 5-minute load average, not instantaneous CPU usage
|
|
39
|
-
CPU_THRESHOLD: 0.
|
|
40
|
-
DISK_THRESHOLD: 0.
|
|
39
|
+
CPU_THRESHOLD: 0.65, // Enqueue if 5-minute load average >= 65% of CPU count
|
|
40
|
+
DISK_THRESHOLD: 0.9, // One-at-a-time if disk usage >= 90%
|
|
41
41
|
|
|
42
42
|
// API limit thresholds (usage ratios: 0.0 - 1.0)
|
|
43
43
|
// All thresholds use >= comparison (inclusive)
|
|
44
|
-
CLAUDE_5_HOUR_SESSION_THRESHOLD: 0.85, //
|
|
44
|
+
CLAUDE_5_HOUR_SESSION_THRESHOLD: 0.85, // One-at-a-time if 5-hour limit >= 85%
|
|
45
45
|
CLAUDE_WEEKLY_THRESHOLD: 0.98, // One-at-a-time if weekly limit >= 98%
|
|
46
|
-
GITHUB_API_THRESHOLD: 0.8, //
|
|
46
|
+
GITHUB_API_THRESHOLD: 0.8, // Enqueue if GitHub >= 80% with parallel claude
|
|
47
47
|
|
|
48
48
|
// Timing
|
|
49
49
|
// MIN_START_INTERVAL_MS: Time to allow solve command to start actual claude process
|
|
@@ -431,11 +431,15 @@ export class SolveQueue {
|
|
|
431
431
|
this.recordThrottle('claude_running');
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
// Check system resources (
|
|
435
|
-
|
|
434
|
+
// Check system resources (RAM, CPU block unconditionally; disk uses one-at-a-time mode)
|
|
435
|
+
// See: https://github.com/link-assistant/hive-mind/issues/1155
|
|
436
|
+
const resourceCheck = await this.checkSystemResources(totalProcessing);
|
|
436
437
|
if (!resourceCheck.ok) {
|
|
437
438
|
reasons.push(...resourceCheck.reasons);
|
|
438
439
|
}
|
|
440
|
+
if (resourceCheck.oneAtATime) {
|
|
441
|
+
oneAtATime = true;
|
|
442
|
+
}
|
|
439
443
|
|
|
440
444
|
// Check API limits (pass hasRunningClaude and totalProcessing for uniform checking)
|
|
441
445
|
const limitCheck = await this.checkApiLimits(hasRunningClaude, totalProcessing);
|
|
@@ -478,17 +482,22 @@ export class SolveQueue {
|
|
|
478
482
|
* This provides a more stable metric that isn't affected by brief spikes
|
|
479
483
|
* during claude process startup.
|
|
480
484
|
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
+
* Resource threshold modes:
|
|
486
|
+
* - RAM_THRESHOLD: Enqueue mode - blocks all commands unconditionally
|
|
487
|
+
* - CPU_THRESHOLD: Enqueue mode - blocks all commands unconditionally
|
|
488
|
+
* - DISK_THRESHOLD: One-at-a-time mode - allows exactly one command when nothing is processing
|
|
489
|
+
*
|
|
490
|
+
* See: https://github.com/link-assistant/hive-mind/issues/1155
|
|
485
491
|
*
|
|
486
|
-
* @
|
|
492
|
+
* @param {number} totalProcessing - Total processing count (queue + external claude processes)
|
|
493
|
+
* @returns {Promise<{ok: boolean, reasons: string[], oneAtATime: boolean}>}
|
|
487
494
|
*/
|
|
488
|
-
async checkSystemResources() {
|
|
495
|
+
async checkSystemResources(totalProcessing = 0) {
|
|
489
496
|
const reasons = [];
|
|
497
|
+
let oneAtATime = false;
|
|
490
498
|
|
|
491
499
|
// Check RAM (using cached value)
|
|
500
|
+
// Enqueue mode: blocks all commands unconditionally
|
|
492
501
|
const memResult = await getCachedMemoryInfo(this.verbose);
|
|
493
502
|
if (memResult.success) {
|
|
494
503
|
const usedRatio = memResult.memory.usedPercentage / 100;
|
|
@@ -499,6 +508,7 @@ export class SolveQueue {
|
|
|
499
508
|
}
|
|
500
509
|
|
|
501
510
|
// Check CPU using 5-minute load average (more stable than 1-minute)
|
|
511
|
+
// Enqueue mode: blocks all commands unconditionally
|
|
502
512
|
// Cache TTL is 2 minutes, which is appropriate for this metric
|
|
503
513
|
const cpuResult = await getCachedCpuInfo(this.verbose);
|
|
504
514
|
if (cpuResult.success) {
|
|
@@ -522,22 +532,26 @@ export class SolveQueue {
|
|
|
522
532
|
}
|
|
523
533
|
|
|
524
534
|
// Check disk space (using cached value)
|
|
525
|
-
//
|
|
526
|
-
// Unlike
|
|
527
|
-
//
|
|
528
|
-
// See: https://github.com/link-assistant/hive-mind/issues/
|
|
535
|
+
// One-at-a-time mode: allows exactly one command when nothing is processing
|
|
536
|
+
// Unlike RAM and CPU which block unconditionally, disk uses one-at-a-time mode
|
|
537
|
+
// because we cannot predict how much disk space a task will use
|
|
538
|
+
// See: https://github.com/link-assistant/hive-mind/issues/1155
|
|
529
539
|
const diskResult = await getCachedDiskInfo(this.verbose);
|
|
530
540
|
if (diskResult.success) {
|
|
531
541
|
// Calculate usage from free percentage
|
|
532
542
|
const usedPercent = 100 - diskResult.diskSpace.freePercentage;
|
|
533
543
|
const usedRatio = usedPercent / 100;
|
|
534
544
|
if (usedRatio >= QUEUE_CONFIG.DISK_THRESHOLD) {
|
|
535
|
-
|
|
545
|
+
oneAtATime = true;
|
|
536
546
|
this.recordThrottle('disk_high');
|
|
547
|
+
// Only block if something is already processing (one-at-a-time mode)
|
|
548
|
+
if (totalProcessing > 0) {
|
|
549
|
+
reasons.push(formatWaitingReason('disk', usedPercent, QUEUE_CONFIG.DISK_THRESHOLD) + ' (waiting for current command)');
|
|
550
|
+
}
|
|
537
551
|
}
|
|
538
552
|
}
|
|
539
553
|
|
|
540
|
-
return { ok: reasons.length === 0, reasons };
|
|
554
|
+
return { ok: reasons.length === 0, reasons, oneAtATime };
|
|
541
555
|
}
|
|
542
556
|
|
|
543
557
|
/**
|