@link-assistant/hive-mind 1.25.6 → 1.25.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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.25.7
4
+
5
+ ### Patch Changes
6
+
7
+ - ad57ea6: fix: prevent false positive error detection when multi-line stderr chunks contain JSON warnings (Issue #1354)
8
+
9
+ 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.
10
+
11
+ 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.
12
+
13
+ Now the fix applies two targeted changes to `src/claude.lib.mjs`:
14
+ 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.
15
+ 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.
16
+
17
+ Full case study analysis including timeline reconstruction, root cause analysis, and evidence in `docs/case-studies/issue-1354/`.
18
+
3
19
  ## 1.25.6
4
20
 
5
21
  ### Patch Changes
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.7",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -846,6 +846,7 @@ export const executeClaudeCommand = async params => {
846
846
  let is503Error = false;
847
847
  let isInternalServerError = false; // Issue #1331: Track 500 Internal server error
848
848
  let stderrErrors = [];
849
+ let resultSuccessReceived = false; // Issue #1354: Track if result success event was received
849
850
  let anthropicTotalCostUSD = null; // Capture Anthropic's official total_cost_usd from result
850
851
  let errorDuringExecution = false; // Issue #1088: Track if error_during_execution subtype occurred
851
852
  let resultSummary = null; // Issue #1263: Capture AI result summary for --attach-solution-summary
@@ -1014,6 +1015,10 @@ export const executeClaudeCommand = async params => {
1014
1015
  await log(`📌 Result event received, starting ${streamCloseTimeoutMs / 1000}s stream close timeout (Issue #1280)`, { verbose: true });
1015
1016
  resultTimeoutId = setTimeout(forceExitOnTimeout, streamCloseTimeoutMs);
1016
1017
  }
1018
+ // Issue #1354: Track when result event confirms success (prevents false positive detection)
1019
+ if (data.subtype === 'success') {
1020
+ resultSuccessReceived = true;
1021
+ }
1017
1022
  // Issue #1104: Only extract cost from subtype 'success' results
1018
1023
  if (data.subtype === 'success' && data.total_cost_usd !== undefined && data.total_cost_usd !== null) {
1019
1024
  anthropicTotalCostUSD = data.total_cost_usd;
@@ -1114,9 +1119,15 @@ export const executeClaudeCommand = async params => {
1114
1119
  // Log stderr immediately
1115
1120
  if (errorOutput) {
1116
1121
  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());
1122
+ // Issue #1354: Split multi-line stderr chunks and check each line individually.
1123
+ // A single chunk may contain multiple newline-separated JSON messages (e.g. two
1124
+ // consecutive {"level":"warn",...} lines). Passing the whole chunk to isStderrError()
1125
+ // causes JSON.parse() to fail (multi-object is not valid JSON), falling through to
1126
+ // keyword matching and producing false positives on words like "failed".
1127
+ for (const line of errorOutput.split('\n')) {
1128
+ if (isStderrError(line)) {
1129
+ stderrErrors.push(line.trim());
1130
+ }
1120
1131
  }
1121
1132
  }
1122
1133
  } else if (chunk.type === 'exit') {
@@ -1255,7 +1266,10 @@ export const executeClaudeCommand = async params => {
1255
1266
  // - Prevents EPERM errors and false success reports
1256
1267
  //
1257
1268
  // See: docs/dependencies-research/claude-code-issues/README.md for full details
1258
- if (!commandFailed && stderrErrors.length > 0 && messageCount === 0 && toolUseCount === 0) {
1269
+ // Issue #1354: Do not trigger if the result event already confirmed success.
1270
+ // A successful result event is definitive proof the command succeeded, regardless of
1271
+ // messageCount (which may be 0 if "assistant" events were counted instead of "message" type).
1272
+ if (!commandFailed && !resultSuccessReceived && stderrErrors.length > 0 && messageCount === 0 && toolUseCount === 0) {
1259
1273
  commandFailed = true;
1260
1274
  const errorsPreview = stderrErrors
1261
1275
  .slice(0, 5)