@link-assistant/hive-mind 1.25.6 → 1.25.8

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,37 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.25.8
4
+
5
+ ### Patch Changes
6
+
7
+ - fix: update system messages to use authenticated curl for private GitHub issue images
8
+
9
+ Images attached to GitHub issues/PRs (github.com/user-attachments/assets/\*) require authentication. Without auth, GitHub returns "Not Found" (9 bytes ASCII) with HTTP 200 — a silent failure. The AI would then call Read on the non-image file, encoding "Not Found" as base64, causing Anthropic API to return "Could not process image" (HTTP 400), crashing the session.
10
+
11
+ Updated system messages in all 4 prompt files (claude, agent, codex, opencode) to explicitly identify user-attachments URLs as requiring GitHub authentication and provide the exact authenticated curl command using `gh auth token`.
12
+
13
+ fix: auto-restart with --resume on "Request timed out" in --tool claude (Issue #1353)
14
+
15
+ When Claude CLI encounters a network timeout, it exhausts its own internal retries and emits a synthetic result event: `{"type":"result","is_error":true,"result":"Request timed out","session_id":"..."}`. Previously hive-mind treated this as a fatal failure and exited, losing all session context (conversation history, cached tokens, partially completed work).
16
+
17
+ This fix detects the timeout pattern and automatically retries with `--resume <session-id>` to preserve the session, using exponential backoff starting at 5 minutes (increasing to max 1 hour) — longer than regular API errors since Claude CLI has already exhausted its own retries before reporting the timeout.
18
+
19
+ ## 1.25.7
20
+
21
+ ### Patch Changes
22
+
23
+ - ad57ea6: fix: prevent false positive error detection when multi-line stderr chunks contain JSON warnings (Issue #1354)
24
+
25
+ Previously, when Claude CLI emitted multiple JSON log lines in a single stderr chunk (newline-separated), the entire multi-line string was passed to `isStderrError()` as one unit. Since `JSON.parse()` would fail on two concatenated JSON objects, it fell through to keyword matching — finding words like `"failed"` inside warning messages — and incorrectly flagged a successful run as an error.
26
+
27
+ Additionally, `messageCount === 0 && toolUseCount === 0` could fire even after a 60-turn successful session, because the counter only checked for `data.type === 'message'` but Claude CLI emits outer events as `"assistant"` type.
28
+
29
+ Now the fix applies two targeted changes to `src/claude.lib.mjs`:
30
+ 1. **Split multi-line stderr chunks by newline** and check each line individually with `isStderrError()`, so valid JSON warning lines are correctly parsed and not conflated with error patterns.
31
+ 2. **Track `resultSuccessReceived`** when `data.type === 'result' && data.subtype === 'success'` is received, and add a `!resultSuccessReceived` guard to the false positive detection condition — ensuring a confirmed successful result prevents spurious error reporting.
32
+
33
+ Full case study analysis including timeline reconstruction, root cause analysis, and evidence in `docs/case-studies/issue-1354/`.
34
+
3
35
  ## 1.25.6
4
36
 
5
37
  ### Patch Changes
package/README.md CHANGED
@@ -192,6 +192,28 @@ docker attach hive-mind
192
192
  # Run bot here
193
193
 
194
194
  # Press Ctrl + P, Ctrl + Q to detach without destroying the container (no stopping of main bash process)
195
+
196
+ # --- Persisting auth data across restarts ---
197
+
198
+ # Extract auth data from a running (or stopped) container to the host:
199
+ mkdir -p ~/.hive-mind
200
+ docker cp hive-mind:/home/hive/.claude ~/.hive-mind/claude
201
+ docker cp hive-mind:/home/hive/.claude.json ~/.hive-mind/claude.json
202
+ docker cp hive-mind:/home/hive/.config/gh ~/.hive-mind/gh
203
+
204
+ # Fix ownership to match the hive user inside the container:
205
+ HIVE_UID=$(docker exec hive-mind id -u hive)
206
+ chown -R $HIVE_UID:$HIVE_UID ~/.hive-mind/claude ~/.hive-mind/gh
207
+ chown $HIVE_UID:$HIVE_UID ~/.hive-mind/claude.json
208
+
209
+ # On subsequent runs, mount the auth data to keep it between restarts:
210
+ docker run -dit \
211
+ --name hive-mind \
212
+ --restart unless-stopped \
213
+ -v /root/.hive-mind/claude:/home/hive/.claude \
214
+ -v /root/.hive-mind/claude.json:/home/hive/.claude.json \
215
+ -v /root/.hive-mind/gh:/home/hive/.config/gh \
216
+ konard/hive-mind:latest
195
217
  ```
196
218
 
197
219
  **Benefits of Docker:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.25.6",
3
+ "version": "1.25.8",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -144,7 +144,7 @@ ${getExperimentsExamplesSubPrompt(argv)}
144
144
  Initial research.
145
145
  - When you start, make sure you create detailed plan for yourself and follow your todo list step by step, make sure that as many points from these guidelines are added to your todo list to keep track of everything that can help you solve the issue with highest possible quality.
146
146
  - When you read issue, read all details and comments thoroughly.
147
- - When you see screenshots or images in issue descriptions, pull request descriptions, comments, or discussions, use WebFetch tool to download the image first, then use Read tool to view and analyze it.
147
+ - When you see screenshots or images in issue descriptions, pull request descriptions, comments, or discussions, download the image to a local file first, then use Read tool to view and analyze it. IMPORTANT: Before reading downloaded images with the Read tool, verify the file is a valid image (not HTML). Use a CLI tool like 'file' command to check the actual file format. If the file command shows "HTML", "text", or "ASCII text", the download FAILED — do NOT call Read on this file. For images from GitHub issues/PRs (URLs containing "github.com/user-attachments"), these require authentication — use: curl -L -H "Authorization: token $(gh auth token)" -o <filename> "<url>"
148
148
  - When you need issue details, use gh issue view https://github.com/${owner}/${repo}/issues/${issueNumber}.
149
149
  - When you need related code, use gh search code --owner ${owner} [keywords].
150
150
  - When you need repo context, read files in your working directory.${
@@ -378,12 +378,6 @@ export const executeClaude = async params => {
378
378
  prNumber,
379
379
  });
380
380
  };
381
- /**
382
- * Calculate total token usage from a session's JSONL file
383
- * @param {string} sessionId - The session ID
384
- * @param {string} tempDir - The temporary directory where the session ran
385
- * @returns {Object} Token usage statistics
386
- */
387
381
  /**
388
382
  * Fetches model information from pricing API
389
383
  * @param {string} modelId - The model ID (e.g., "claude-sonnet-4-5-20250929")
@@ -845,7 +839,9 @@ export const executeClaudeCommand = async params => {
845
839
  let isOverloadError = false;
846
840
  let is503Error = false;
847
841
  let isInternalServerError = false; // Issue #1331: Track 500 Internal server error
842
+ let isRequestTimeout = false; // Issue #1353: Track "Request timed out" from Claude CLI
848
843
  let stderrErrors = [];
844
+ let resultSuccessReceived = false; // Issue #1354: Track if result success event was received
849
845
  let anthropicTotalCostUSD = null; // Capture Anthropic's official total_cost_usd from result
850
846
  let errorDuringExecution = false; // Issue #1088: Track if error_during_execution subtype occurred
851
847
  let resultSummary = null; // Issue #1263: Capture AI result summary for --attach-solution-summary
@@ -1014,6 +1010,10 @@ export const executeClaudeCommand = async params => {
1014
1010
  await log(`📌 Result event received, starting ${streamCloseTimeoutMs / 1000}s stream close timeout (Issue #1280)`, { verbose: true });
1015
1011
  resultTimeoutId = setTimeout(forceExitOnTimeout, streamCloseTimeoutMs);
1016
1012
  }
1013
+ // Issue #1354: Track when result event confirms success (prevents false positive detection)
1014
+ if (data.subtype === 'success') {
1015
+ resultSuccessReceived = true;
1016
+ }
1017
1017
  // Issue #1104: Only extract cost from subtype 'success' results
1018
1018
  if (data.subtype === 'success' && data.total_cost_usd !== undefined && data.total_cost_usd !== null) {
1019
1019
  anthropicTotalCostUSD = data.total_cost_usd;
@@ -1045,6 +1045,11 @@ export const executeClaudeCommand = async params => {
1045
1045
  if (lastMessage.includes('Internal server error') && !lastMessage.includes('Overloaded')) {
1046
1046
  isInternalServerError = true;
1047
1047
  }
1048
+ // Issue #1353: Detect "Request timed out" — Claude CLI emits {type:"result",is_error:true,result:"Request timed out"} after exhausting retries
1049
+ if (lastMessage === 'Request timed out' || lastMessage.includes('Request timed out')) {
1050
+ isRequestTimeout = true;
1051
+ await log('⏱️ Detected request timeout from Claude CLI (will retry with --resume)', { verbose: true });
1052
+ }
1048
1053
  }
1049
1054
  }
1050
1055
  // Store last message for error detection
@@ -1077,6 +1082,12 @@ export const executeClaudeCommand = async params => {
1077
1082
  lastMessage = item.text;
1078
1083
  await log('⚠️ Detected 503 network error', { verbose: true });
1079
1084
  }
1085
+ // Issue #1353: Detect "Request timed out" in assistant text content
1086
+ if (item.text === 'Request timed out' || item.text.includes('Request timed out')) {
1087
+ isRequestTimeout = true;
1088
+ lastMessage = item.text;
1089
+ await log('⏱️ Detected request timeout in assistant message (will retry with --resume)', { verbose: true });
1090
+ }
1080
1091
  }
1081
1092
  }
1082
1093
  }
@@ -1114,9 +1125,15 @@ export const executeClaudeCommand = async params => {
1114
1125
  // Log stderr immediately
1115
1126
  if (errorOutput) {
1116
1127
  await log(errorOutput, { stream: 'stderr' });
1117
- // Track stderr errors for failure detection using shared helper (Issue #477, #1165, #1337)
1118
- if (isStderrError(errorOutput)) {
1119
- stderrErrors.push(errorOutput.trim());
1128
+ // Issue #1354: Split multi-line stderr chunks and check each line individually.
1129
+ // A single chunk may contain multiple newline-separated JSON messages (e.g. two
1130
+ // consecutive {"level":"warn",...} lines). Passing the whole chunk to isStderrError()
1131
+ // causes JSON.parse() to fail (multi-object is not valid JSON), falling through to
1132
+ // keyword matching and producing false positives on words like "failed".
1133
+ for (const line of errorOutput.split('\n')) {
1134
+ if (isStderrError(line)) {
1135
+ stderrErrors.push(line.trim());
1136
+ }
1120
1137
  }
1121
1138
  }
1122
1139
  } else if (chunk.type === 'exit') {
@@ -1177,13 +1194,19 @@ export const executeClaudeCommand = async params => {
1177
1194
  }
1178
1195
 
1179
1196
  // Issue #1331: Unified handler for all transient API errors (Overloaded, 503, Internal Server Error)
1180
- // All use same params: 10 retries, 1min initial, 30min max, exponential backoff, session preserved
1181
- const isTransientError = isOverloadError || isInternalServerError || is503Error || (lastMessage.includes('API Error: 500') && (lastMessage.includes('Overloaded') || lastMessage.includes('Internal server error'))) || (lastMessage.includes('api_error') && lastMessage.includes('Overloaded')) || lastMessage.includes('API Error: 503') || (lastMessage.includes('503') && (lastMessage.includes('upstream connect error') || lastMessage.includes('remote connection failure')));
1197
+ // Issue #1353: Also handle "Request timed out" Claude CLI times out after exhausting its own retries
1198
+ // All use exponential backoff with session preservation via --resume
1199
+ const isTransientError = isOverloadError || isInternalServerError || is503Error || isRequestTimeout || (lastMessage.includes('API Error: 500') && (lastMessage.includes('Overloaded') || lastMessage.includes('Internal server error'))) || (lastMessage.includes('api_error') && lastMessage.includes('Overloaded')) || lastMessage.includes('API Error: 503') || (lastMessage.includes('503') && (lastMessage.includes('upstream connect error') || lastMessage.includes('remote connection failure'))) || lastMessage === 'Request timed out' || lastMessage.includes('Request timed out');
1182
1200
  if ((commandFailed || isTransientError) && isTransientError) {
1183
- if (retryCount < retryLimits.maxTransientErrorRetries) {
1184
- const delay = Math.min(retryLimits.initialTransientErrorDelayMs * Math.pow(retryLimits.retryBackoffMultiplier, retryCount), retryLimits.maxTransientErrorDelayMs);
1185
- const errorLabel = isOverloadError || (lastMessage.includes('API Error: 500') && lastMessage.includes('Overloaded')) ? 'API overload (500)' : isInternalServerError || lastMessage.includes('Internal server error') ? 'Internal server error (500)' : '503 network error';
1186
- await log(`\n⚠️ ${errorLabel} detected. Retry ${retryCount + 1}/${retryLimits.maxTransientErrorRetries} in ${Math.round(delay / 60000)} min (session preserved)...`, { level: 'warning' });
1201
+ // Issue #1353: Use timeout-specific backoff params (5min–1hr) vs general transient params (1min–30min)
1202
+ // Timeouts indicate network instability Claude CLI already exhausted its own retries, so we need longer waits
1203
+ const maxRetries = isRequestTimeout ? retryLimits.maxRequestTimeoutRetries : retryLimits.maxTransientErrorRetries;
1204
+ const initialDelay = isRequestTimeout ? retryLimits.initialRequestTimeoutDelayMs : retryLimits.initialTransientErrorDelayMs;
1205
+ const maxDelay = isRequestTimeout ? retryLimits.maxRequestTimeoutDelayMs : retryLimits.maxTransientErrorDelayMs;
1206
+ if (retryCount < maxRetries) {
1207
+ const delay = Math.min(initialDelay * Math.pow(retryLimits.retryBackoffMultiplier, retryCount), maxDelay);
1208
+ const errorLabel = isRequestTimeout ? 'Request timeout' : isOverloadError || (lastMessage.includes('API Error: 500') && lastMessage.includes('Overloaded')) ? 'API overload (500)' : isInternalServerError || lastMessage.includes('Internal server error') ? 'Internal server error (500)' : '503 network error';
1209
+ await log(`\n⚠️ ${errorLabel} detected. Retry ${retryCount + 1}/${maxRetries} in ${Math.round(delay / 60000)} min (session preserved)...`, { level: 'warning' });
1187
1210
  await log(` Error: ${lastMessage.substring(0, 200)}`, { verbose: true });
1188
1211
  if (sessionId && !argv.resume) argv.resume = sessionId; // preserve session for resume
1189
1212
  await waitWithCountdown(delay, log);
@@ -1191,7 +1214,7 @@ export const executeClaudeCommand = async params => {
1191
1214
  retryCount++;
1192
1215
  return await executeWithRetry();
1193
1216
  } else {
1194
- await log(`\n\n❌ Transient API error persisted after ${retryLimits.maxTransientErrorRetries} retries\n Please try again later or check https://status.anthropic.com/`, { level: 'error' });
1217
+ await log(`\n\n❌ Transient API error persisted after ${maxRetries} retries\n Please try again later or check https://status.anthropic.com/`, { level: 'error' });
1195
1218
  return {
1196
1219
  success: false,
1197
1220
  sessionId,
@@ -1236,26 +1259,10 @@ export const executeClaudeCommand = async params => {
1236
1259
  }
1237
1260
  }
1238
1261
  }
1239
- // Additional failure detection: if no messages were processed and there were stderr errors,
1240
- // or if the command produced no output at all, treat it as a failure
1241
- //
1242
- // This is critical for detecting "silent failures" where:
1243
- // 1. Claude CLI encounters an internal error (e.g., "kill EPERM" from timeout)
1244
- // 2. The error is logged to stderr but exit code is 0 or exit event is never sent
1245
- // 3. Result: messageCount=0, toolUseCount=0, but stderrErrors has content
1246
- //
1247
- // Common cause: sudo commands that timeout
1248
- // - Timeout triggers process.kill() in Claude CLI
1249
- // - If child process runs with sudo (root), parent can't kill it → EPERM error
1250
- // - Error logged to stderr, but command doesn't properly fail
1251
- //
1252
- // Workaround (applied in system prompt):
1253
- // - Instruct Claude to run sudo commands (installations) in background
1254
- // - Background processes avoid timeout kill mechanism
1255
- // - Prevents EPERM errors and false success reports
1256
- //
1257
- // See: docs/dependencies-research/claude-code-issues/README.md for full details
1258
- if (!commandFailed && stderrErrors.length > 0 && messageCount === 0 && toolUseCount === 0) {
1262
+ // Additional failure detection: silent failures (no messages + stderr errors).
1263
+ // E.g., sudo timeout causing "kill EPERM" stderr error but exit code 0.
1264
+ // Issue #1354: Skip if result event confirmed success (definitive proof regardless of messageCount).
1265
+ if (!commandFailed && !resultSuccessReceived && stderrErrors.length > 0 && messageCount === 0 && toolUseCount === 0) {
1259
1266
  commandFailed = true;
1260
1267
  const errorsPreview = stderrErrors
1261
1268
  .slice(0, 5)
@@ -1363,13 +1370,19 @@ export const executeClaudeCommand = async params => {
1363
1370
  });
1364
1371
  const errorStr = error.message || error.toString();
1365
1372
  // Issue #1331: Unified handler for all transient API errors in exception block
1366
- // (Overloaded, 503, Internal Server Error) - same params, all with session preservation
1367
- const isTransientException = (errorStr.includes('API Error: 500') && (errorStr.includes('Overloaded') || errorStr.includes('Internal server error'))) || (errorStr.includes('api_error') && errorStr.includes('Overloaded')) || errorStr.includes('API Error: 503') || (errorStr.includes('503') && (errorStr.includes('upstream connect error') || errorStr.includes('remote connection failure')));
1373
+ // Issue #1353: Also handle "Request timed out" in exception block
1374
+ // (Overloaded, 503, Internal Server Error, Request timed out) - all with session preservation
1375
+ const isTimeoutException = errorStr === 'Request timed out' || errorStr.includes('Request timed out');
1376
+ const isTransientException = isTimeoutException || (errorStr.includes('API Error: 500') && (errorStr.includes('Overloaded') || errorStr.includes('Internal server error'))) || (errorStr.includes('api_error') && errorStr.includes('Overloaded')) || errorStr.includes('API Error: 503') || (errorStr.includes('503') && (errorStr.includes('upstream connect error') || errorStr.includes('remote connection failure')));
1368
1377
  if (isTransientException) {
1369
- if (retryCount < retryLimits.maxTransientErrorRetries) {
1370
- const delay = Math.min(retryLimits.initialTransientErrorDelayMs * Math.pow(retryLimits.retryBackoffMultiplier, retryCount), retryLimits.maxTransientErrorDelayMs);
1371
- const errorLabel = errorStr.includes('Overloaded') ? 'API overload (500)' : errorStr.includes('Internal server error') ? 'Internal server error (500)' : '503 network error';
1372
- await log(`\n⚠️ ${errorLabel} in exception. Retry ${retryCount + 1}/${retryLimits.maxTransientErrorRetries} in ${Math.round(delay / 60000)} min (session preserved)...`, { level: 'warning' });
1378
+ // Issue #1353: Use timeout-specific backoff for request timeouts
1379
+ const maxRetries = isTimeoutException ? retryLimits.maxRequestTimeoutRetries : retryLimits.maxTransientErrorRetries;
1380
+ const initialDelay = isTimeoutException ? retryLimits.initialRequestTimeoutDelayMs : retryLimits.initialTransientErrorDelayMs;
1381
+ const maxDelay = isTimeoutException ? retryLimits.maxRequestTimeoutDelayMs : retryLimits.maxTransientErrorDelayMs;
1382
+ if (retryCount < maxRetries) {
1383
+ const delay = Math.min(initialDelay * Math.pow(retryLimits.retryBackoffMultiplier, retryCount), maxDelay);
1384
+ const errorLabel = isTimeoutException ? 'Request timeout' : errorStr.includes('Overloaded') ? 'API overload (500)' : errorStr.includes('Internal server error') ? 'Internal server error (500)' : '503 network error';
1385
+ await log(`\n⚠️ ${errorLabel} in exception. Retry ${retryCount + 1}/${maxRetries} in ${Math.round(delay / 60000)} min (session preserved)...`, { level: 'warning' });
1373
1386
  if (sessionId && !argv.resume) argv.resume = sessionId;
1374
1387
  await waitWithCountdown(delay, log);
1375
1388
  await log('\n🔄 Retrying now...');
@@ -171,7 +171,7 @@ Initial research.
171
171
  - When you start, make sure you create detailed plan for yourself and follow your todo list step by step, make sure that as many points from these guidelines are added to your todo list to keep track of everything that can help you solve the issue with highest possible quality.
172
172
  - When user mentions CI failures or asks to investigate logs, consider adding these todos to track the investigation: (1) List recent CI runs with timestamps, (2) Download logs from failed runs to ci-logs/ directory, (3) Analyze error messages and identify root cause, (4) Implement fix, (5) Verify fix resolves the specific errors found in logs.
173
173
  - When you read issue, read all details and comments thoroughly.
174
- - When you see screenshots or images in issue descriptions, pull request descriptions, comments, or discussions, use WebFetch tool (or fetch tool) to download the image first, then use Read tool to view and analyze it. IMPORTANT: Before reading downloaded images with the Read tool, verify the file is a valid image (not HTML). Use a CLI tool like 'file' command to check the actual file format. Reading corrupted or non-image files (like GitHub's HTML 404 pages saved as .png) can cause "Could not process image" errors and may crash the AI solver process. If the file command shows "HTML" or "text", the download failed and you should retry or skip the image.
174
+ - When you see screenshots or images in issue descriptions, pull request descriptions, comments, or discussions, download the image to a local file first, then use Read tool to view and analyze it. IMPORTANT: Before reading downloaded images with the Read tool, verify the file is a valid image (not HTML). Use a CLI tool like 'file' command to check the actual file format. Reading corrupted or non-image files (like GitHub's "Not Found" pages saved as .png) can cause "Could not process image" errors and will crash the AI solver process. If the file command shows "HTML", "text", or "ASCII text", the download FAILED do NOT call Read on this file. Instead: (1) For images from GitHub issues/PRs (URLs containing "github.com/user-attachments"), these require authentication — retry with: curl -L -H "Authorization: token $(gh auth token)" -o <filename> "<url>" (2) If retry still fails, skip the image and note it was unavailable.
175
175
  - When you need issue details, use gh issue view https://github.com/${owner}/${repo}/issues/${issueNumber}.
176
176
  - When you need related code, use gh search code --owner ${owner} [keywords].
177
177
  - When you need repo context, read files in your working directory.${
@@ -152,7 +152,7 @@ Initial research.
152
152
  - When you start, make sure you create detailed plan for yourself and follow your todo list step by step, make sure that as many points from these guidelines are added to your todo list to keep track of everything that can help you solve the issue with highest possible quality.
153
153
  - When user mentions CI failures or asks to investigate logs, consider adding these todos to track the investigation: (1) List recent CI runs with timestamps, (2) Download logs from failed runs to ci-logs/ directory, (3) Analyze error messages and identify root cause, (4) Implement fix, (5) Verify fix resolves the specific errors found in logs.
154
154
  - When you read issue, read all details and comments thoroughly.
155
- - When you see screenshots or images in issue descriptions, pull request descriptions, comments, or discussions, use WebFetch tool (or fetch tool) to download the image first, then use Read tool to view and analyze it.
155
+ - When you see screenshots or images in issue descriptions, pull request descriptions, comments, or discussions, download the image to a local file first, then use Read tool to view and analyze it. IMPORTANT: Before reading downloaded images with the Read tool, verify the file is a valid image (not HTML). Use a CLI tool like 'file' command to check the actual file format. If the file command shows "HTML", "text", or "ASCII text", the download FAILED — do NOT call Read on this file. For images from GitHub issues/PRs (URLs containing "github.com/user-attachments"), these require authentication — use: curl -L -H "Authorization: token $(gh auth token)" -o <filename> "<url>"
156
156
  - When you need issue details, use gh issue view https://github.com/${owner}/${repo}/issues/${issueNumber}.
157
157
  - When you need related code, use gh search code --owner ${owner} [keywords].
158
158
  - When you need repo context, read files in your working directory.${
@@ -103,6 +103,11 @@ export const retryLimits = {
103
103
  maxTransientErrorRetries: parseIntWithDefault('HIVE_MIND_MAX_TRANSIENT_ERROR_RETRIES', 10),
104
104
  initialTransientErrorDelayMs: parseIntWithDefault('HIVE_MIND_INITIAL_TRANSIENT_ERROR_DELAY_MS', 60 * 1000), // 1 minute
105
105
  maxTransientErrorDelayMs: parseIntWithDefault('HIVE_MIND_MAX_TRANSIENT_ERROR_DELAY_MS', 30 * 60 * 1000), // 30 minutes
106
+ // Request timeout retry configuration (Issue #1353)
107
+ // Network timeouts need longer waits than API errors — Claude CLI already exhausted its own retries
108
+ maxRequestTimeoutRetries: parseIntWithDefault('HIVE_MIND_MAX_REQUEST_TIMEOUT_RETRIES', 10),
109
+ initialRequestTimeoutDelayMs: parseIntWithDefault('HIVE_MIND_INITIAL_REQUEST_TIMEOUT_DELAY_MS', 5 * 60 * 1000), // 5 minutes
110
+ maxRequestTimeoutDelayMs: parseIntWithDefault('HIVE_MIND_MAX_REQUEST_TIMEOUT_DELAY_MS', 60 * 60 * 1000), // 1 hour
106
111
  };
107
112
 
108
113
  // Claude Code CLI configurations
@@ -146,7 +146,7 @@ ${workspaceInstructions}
146
146
  Initial research.
147
147
  - When you start, make sure you create detailed plan for yourself and follow your todo list step by step, make sure that as many points from these guidelines are added to your todo list to keep track of everything that can help you solve the issue with highest possible quality.
148
148
  - When you read issue, read all details and comments thoroughly.
149
- - When you see screenshots or images in issue descriptions, pull request descriptions, comments, or discussions, use WebFetch tool to download the image first, then use Read tool to view and analyze it. IMPORTANT: Before reading downloaded images with the Read tool, verify the file is a valid image (not HTML). Use a CLI tool like 'file' command to check the actual file format. Reading corrupted or non-image files (like GitHub's HTML 404 pages saved as .png) can cause "Could not process image" errors and may crash the AI solver process. If the file command shows "HTML" or "text", the download failed and you should retry or skip the image.
149
+ - When you see screenshots or images in issue descriptions, pull request descriptions, comments, or discussions, download the image to a local file first, then use Read tool to view and analyze it. IMPORTANT: Before reading downloaded images with the Read tool, verify the file is a valid image (not HTML). Use a CLI tool like 'file' command to check the actual file format. Reading corrupted or non-image files (like GitHub's "Not Found" pages saved as .png) can cause "Could not process image" errors and will crash the AI solver process. If the file command shows "HTML", "text", or "ASCII text", the download FAILED do NOT call Read on this file. Instead: (1) For images from GitHub issues/PRs (URLs containing "github.com/user-attachments"), these require authentication — retry with: curl -L -H "Authorization: token $(gh auth token)" -o <filename> "<url>" (2) If retry still fails, skip the image and note it was unavailable.
150
150
  - When you need issue details, use gh issue view https://github.com/${owner}/${repo}/issues/${issueNumber}.
151
151
  - When you need related code, use gh search code --owner ${owner} [keywords].
152
152
  - When you need repo context, read files in your working directory.${