@link-assistant/hive-mind 0.54.0 → 0.54.1

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,18 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 0.54.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 55576af: fix: allow parallel queue execution when no limits exceeded
8
+
9
+ Previously, "Claude process is already running" was treated as a blocking reason on its own, preventing parallel execution even when all system and API limits were within thresholds.
10
+
11
+ Changes:
12
+ - `claude_running` is now tracked as a metric, not a blocking reason
13
+ - Commands can run in parallel as long as actual limits are not exceeded
14
+ - When any limit >= threshold, allow exactly one claude command to pass
15
+
3
16
  ## 0.54.0
4
17
 
5
18
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "0.54.0",
3
+ "version": "0.54.1",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -357,6 +357,12 @@ export class SolveQueue {
357
357
 
358
358
  /**
359
359
  * Check if a new command can start
360
+ *
361
+ * Logic per issue #1061:
362
+ * 1. "Claude process is already running" is NOT a limit by itself - it's a metric
363
+ * 2. Commands can run in parallel as long as actual limits are not exceeded
364
+ * 3. When any limit >= threshold, allow exactly one claude command to pass
365
+ *
360
366
  * @returns {Promise<{canStart: boolean, reason?: string, reasons?: string[], oneAtATime?: boolean}>}
361
367
  */
362
368
  async canStartCommand() {
@@ -373,10 +379,12 @@ export class SolveQueue {
373
379
  }
374
380
  }
375
381
 
376
- // Check running claude processes
382
+ // Check running claude processes (this is a metric, not a blocking reason by itself)
377
383
  const claudeProcs = await getRunningClaudeProcesses(this.verbose);
378
- if (claudeProcs.count > 0) {
379
- reasons.push(formatWaitingReason('claude_running', claudeProcs.count, 0) + ` (${claudeProcs.count} processes)`);
384
+ const hasRunningClaude = claudeProcs.count > 0;
385
+
386
+ // Track claude_running as a metric (but don't add to reasons yet)
387
+ if (hasRunningClaude) {
380
388
  this.recordThrottle('claude_running');
381
389
  }
382
390
 
@@ -389,8 +397,8 @@ export class SolveQueue {
389
397
  oneAtATime = true;
390
398
  }
391
399
 
392
- // Check API limits
393
- const limitCheck = await this.checkApiLimits(claudeProcs.count > 0);
400
+ // Check API limits (pass hasRunningClaude to enable special handling)
401
+ const limitCheck = await this.checkApiLimits(hasRunningClaude);
394
402
  if (!limitCheck.ok) {
395
403
  reasons.push(...limitCheck.reasons);
396
404
  }
@@ -398,6 +406,13 @@ export class SolveQueue {
398
406
  oneAtATime = true;
399
407
  }
400
408
 
409
+ // "Claude process running" only blocks if there are OTHER reasons too
410
+ // This allows parallel execution when limits are not exceeded
411
+ if (hasRunningClaude && reasons.length > 0) {
412
+ // Add claude_running info only when combined with actual limit reasons
413
+ reasons.unshift(formatWaitingReason('claude_running', claudeProcs.count, 0) + ` (${claudeProcs.count} processes)`);
414
+ }
415
+
401
416
  const canStart = reasons.length === 0;
402
417
 
403
418
  if (!canStart && this.verbose) {
@@ -461,6 +476,12 @@ export class SolveQueue {
461
476
 
462
477
  /**
463
478
  * Check API limits (Claude, GitHub) using cached values
479
+ *
480
+ * Simplified logic per issue #1061:
481
+ * - When any limit >= threshold, allow exactly one claude command to pass
482
+ * - Only block if there's already a command in progress
483
+ * - Running claude is the ultimate test of whether limits are really exhausted
484
+ *
464
485
  * @param {boolean} hasRunningClaude - Whether claude processes are running
465
486
  * @returns {Promise<{ok: boolean, reasons: string[], oneAtATime: boolean}>}
466
487
  */
@@ -475,29 +496,26 @@ export class SolveQueue {
475
496
  const weeklyPercent = claudeResult.usage.allModels.percentage;
476
497
 
477
498
  // Session limit (5-hour)
499
+ // When above threshold: allow exactly one command, block if one is running
478
500
  if (sessionPercent !== null) {
479
501
  const sessionRatio = sessionPercent / 100;
480
- if (sessionRatio >= 1.0) {
481
- reasons.push('Claude session limit is 100% (waiting for reset)');
482
- this.recordThrottle('claude_session_100');
483
- } else if (sessionRatio >= QUEUE_CONFIG.CLAUDE_SESSION_THRESHOLD) {
484
- reasons.push(formatWaitingReason('claude_session', sessionPercent, QUEUE_CONFIG.CLAUDE_SESSION_THRESHOLD));
485
- this.recordThrottle('claude_session_high');
502
+ if (sessionRatio >= QUEUE_CONFIG.CLAUDE_SESSION_THRESHOLD) {
503
+ // Only block if Claude is already running
504
+ if (hasRunningClaude) {
505
+ reasons.push(formatWaitingReason('claude_session', sessionPercent, QUEUE_CONFIG.CLAUDE_SESSION_THRESHOLD));
506
+ }
507
+ this.recordThrottle(sessionRatio >= 1.0 ? 'claude_session_100' : 'claude_session_high');
486
508
  }
487
509
  }
488
510
 
489
511
  // Weekly limit
512
+ // When above threshold: allow exactly one command, block if one is in progress
490
513
  if (weeklyPercent !== null) {
491
514
  const weeklyRatio = weeklyPercent / 100;
492
- if (weeklyRatio >= 1.0) {
493
- oneAtATime = true;
494
- this.recordThrottle('claude_weekly_100');
495
- if (this.processing.size > 0) {
496
- reasons.push('Claude weekly limit is 100% (waiting for current command)');
497
- }
498
- } else if (weeklyRatio >= QUEUE_CONFIG.CLAUDE_WEEKLY_THRESHOLD) {
515
+ if (weeklyRatio >= QUEUE_CONFIG.CLAUDE_WEEKLY_THRESHOLD) {
499
516
  oneAtATime = true;
500
- this.recordThrottle('claude_weekly_high');
517
+ this.recordThrottle(weeklyRatio >= 1.0 ? 'claude_weekly_100' : 'claude_weekly_high');
518
+ // Only block if command is already in progress
501
519
  if (this.processing.size > 0) {
502
520
  reasons.push(formatWaitingReason('claude_weekly', weeklyPercent, QUEUE_CONFIG.CLAUDE_WEEKLY_THRESHOLD) + ' (waiting for current command)');
503
521
  }
@@ -511,12 +529,9 @@ export class SolveQueue {
511
529
  if (githubResult.success) {
512
530
  const usedPercent = githubResult.githubRateLimit.usedPercentage;
513
531
  const usedRatio = usedPercent / 100;
514
- if (usedRatio >= 1.0) {
515
- reasons.push('GitHub API limit is 100% (waiting for reset)');
516
- this.recordThrottle('github_100');
517
- } else if (usedRatio >= QUEUE_CONFIG.GITHUB_API_THRESHOLD) {
532
+ if (usedRatio >= QUEUE_CONFIG.GITHUB_API_THRESHOLD) {
518
533
  reasons.push(formatWaitingReason('github', usedPercent, QUEUE_CONFIG.GITHUB_API_THRESHOLD));
519
- this.recordThrottle('github_high');
534
+ this.recordThrottle(usedRatio >= 1.0 ? 'github_100' : 'github_high');
520
535
  }
521
536
  }
522
537
  }