@link-assistant/hive-mind 1.74.9 → 1.74.10

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,11 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.74.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 88adc75: Fix the auto-resume wait calculation for weekly `--tool codex` usage limits (Issue #1869, phase 2). After the display parser was fixed to keep the full reset date, the separate auto-resume parser in `solve.validation.lib.mjs` still crashed with `Invalid time format: Jun 11, 2026, 12:27 AM` and, even when it parsed, discarded the date and scheduled for today/tomorrow — so auto-resume woke up far too early. `calculateWaitTime` now delegates to the robust date-aware `parseResetTime` from `usage-limit.lib.mjs` (honoring explicit year, weekly date, and timezone) and returns the real time-until-reset, and all three call sites now forward the timezone. This consolidates onto a single reset-time parser.
8
+
3
9
  ## 1.74.9
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.74.9",
3
+ "version": "1.74.10",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -92,7 +92,7 @@ export const autoContinueWhenLimitResets = async (issueUrl, sessionId, argv, sho
92
92
  const nextAutoResumeIteration = currentAutoResumeIteration + 1;
93
93
  const resetTime = global.limitResetTime;
94
94
  const timezone = global.limitTimezone || null;
95
- const baseWaitMs = calculateWaitTime(resetTime);
95
+ const baseWaitMs = calculateWaitTime(resetTime, timezone);
96
96
 
97
97
  // Add buffer time after limit reset to account for server time differences
98
98
  // Default: 10 minutes (configurable via HIVE_MIND_LIMIT_RESET_BUFFER_MS)
@@ -735,7 +735,7 @@ No further AI sessions will be started automatically for this run. Please review
735
735
  limitResumeCount++;
736
736
  const resumeSessionId = toolResult.sessionId;
737
737
  const resetTime = toolResult.limitResetTime;
738
- const baseWaitMs = resetTime ? calculateWaitTime(resetTime) : 0;
738
+ const baseWaitMs = resetTime ? calculateWaitTime(resetTime, toolResult.limitTimezone || null) : 0;
739
739
  const bufferMs = limitReset.bufferMs;
740
740
  const jitterMs = Math.floor(Math.random() * limitReset.jitterMs);
741
741
  const waitMs = baseWaitMs + bufferMs + jitterMs;
package/src/solve.mjs CHANGED
@@ -1029,7 +1029,7 @@ try {
1029
1029
  // Calculate wait time in d:h:m:s format
1030
1030
  const validation = await import('./solve.validation.lib.mjs');
1031
1031
  const { calculateWaitTime } = validation;
1032
- const waitMs = calculateWaitTime(global.limitResetTime);
1032
+ const waitMs = calculateWaitTime(global.limitResetTime, global.limitTimezone || null);
1033
1033
 
1034
1034
  const formatWaitTime = ms => {
1035
1035
  const seconds = Math.floor(ms / 1000);
@@ -43,6 +43,13 @@ const claudeLib = await import('./claude.lib.mjs');
43
43
  const sentryLib = await import('./sentry.lib.mjs');
44
44
  const { reportError } = sentryLib;
45
45
 
46
+ // Import the robust usage-limit reset-time parser.
47
+ // This returns a full dayjs date (honoring an explicit year and timezone) so the
48
+ // auto-resume wait calculation can respect weekly limits that are days out, rather
49
+ // than collapsing every reset to "today/tomorrow at HH:MM" (Issue #1869).
50
+ const usageLimitLib = await import('./usage-limit.lib.mjs');
51
+ const { parseResetTime: parseResetTimeToDate } = usageLimitLib;
52
+
46
53
  const { validateClaudeConnection } = claudeLib;
47
54
 
48
55
  // Wrapper function for disk space check using imported module
@@ -394,13 +401,23 @@ export const parseUrlComponents = issueUrl => {
394
401
  };
395
402
  };
396
403
 
397
- // Helper function to parse time string and calculate wait time
404
+ // Helper function to parse a reset time string into hour/minute components.
405
+ //
406
+ // Accepts:
407
+ // - Time-only forms: "5:30am", "11:45pm", "12:16 PM", "07:05 Am", "5am", "5 AM"
408
+ // - Date+time forms: "Apr 17, 4:00 AM" (date portion ignored)
409
+ // - Date+year+time forms: "Jun 11, 2026, 12:27 AM" (date+year ignored — Issue #1869)
410
+ //
411
+ // NOTE: This helper only extracts the time-of-day. For computing the actual wait
412
+ // duration use calculateWaitTime(), which preserves the full date so weekly limits
413
+ // (which can be days away) are honored instead of being collapsed to today/tomorrow.
398
414
  export const parseResetTime = timeStr => {
399
- // Normalize and parse time formats like:
400
- // "5:30am", "11:45pm", "12:16 PM", "07:05 Am", "5am", "5 AM"
401
- // Also accepts date+time forms like "Apr 17, 4:00 AM" and ignores the date portion.
402
415
  const normalized = (timeStr || '').toString().trim();
403
- const timePortion = normalized.replace(/^(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\s+\d{1,2},\s+/i, '');
416
+ // Strip an optional leading "Month Day," and an optional "Year," so the
417
+ // remaining string is just the time-of-day. The year group (Issue #1869) makes
418
+ // Codex weekly-limit strings like "Jun 11, 2026, 12:27 AM" parse instead of
419
+ // throwing "Invalid time format".
420
+ const timePortion = normalized.replace(/^(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\s+\d{1,2}(?:st|nd|rd|th)?,\s+(?:\d{4},\s+)?/i, '');
404
421
 
405
422
  // Accept both HH:MM am/pm and HH am/pm
406
423
  let match = timePortion.match(/^(\d{1,2})(?::(\d{2}))?\s*([ap]m)$/i);
@@ -423,8 +440,32 @@ export const parseResetTime = timeStr => {
423
440
  return { hour, minute };
424
441
  };
425
442
 
426
- // Calculate milliseconds until the next occurrence of the specified time
427
- export const calculateWaitTime = resetTime => {
443
+ // Calculate milliseconds until the limit reset.
444
+ //
445
+ // Issue #1869: This MUST respect the full reset date (including an explicit year),
446
+ // not just the time-of-day. A weekly Codex limit reports "Jun 11th, 2026 12:27 AM"
447
+ // which can be days in the future; the previous implementation only looked at the
448
+ // hour/minute and scheduled for today/tomorrow, so auto-resume woke up far too early
449
+ // and burned an auto-resume iteration without the limit actually having reset.
450
+ //
451
+ // We delegate to the robust usage-limit parser, which returns a full dayjs date that
452
+ // already handles: explicit year, weekly date+time, time-only (rolls forward to the
453
+ // next occurrence), and an optional IANA timezone. We then return the real diff.
454
+ //
455
+ // @param {string} resetTime - Reset time string (time-only, date+time, or date+year+time)
456
+ // @param {string|null} timezone - Optional IANA timezone (e.g. "Europe/Berlin")
457
+ // @returns {number} - Milliseconds until reset (never negative)
458
+ export const calculateWaitTime = (resetTime, timezone = null) => {
459
+ const resetDate = parseResetTimeToDate(resetTime, timezone);
460
+
461
+ if (resetDate && resetDate.isValid()) {
462
+ const diffMs = resetDate.valueOf() - Date.now();
463
+ return diffMs > 0 ? diffMs : 0;
464
+ }
465
+
466
+ // Fallback: the robust parser could not interpret the string. Fall back to the
467
+ // legacy time-of-day behavior (today/tomorrow) so we still wait a sensible amount
468
+ // rather than throwing — parseResetTime throws for genuinely unparseable input.
428
469
  const { hour, minute } = parseResetTime(resetTime);
429
470
 
430
471
  const now = new Date();