@link-assistant/hive-mind 1.24.4 → 1.24.5

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,17 @@
1
1
  # @link-assistant/hive-mind
2
2
 
3
+ ## 1.24.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 17317bb: fix: prevent false positive error detection for JSON-structured stderr warnings (Issue #1337)
8
+
9
+ Claude Code SDK can emit structured JSON log messages to stderr with format `{"level":"warn","message":"..."}`. When these messages contained error-related keywords like "failed", the detection logic incorrectly flagged them as errors.
10
+
11
+ Added JSON parsing for stderr messages starting with `{`. If the parsed JSON has a `level` field that is not `"error"` or `"fatal"`, the message is treated as a warning (non-error), preserving existing emoji-prefix detection as a fallback.
12
+
13
+ Also enables `ANTHROPIC_LOG=debug` when running with `--verbose` flag, allowing users to see detailed API request information as suggested by the BashTool pre-flight warning.
14
+
3
15
  ## 1.24.4
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-assistant/hive-mind",
3
- "version": "1.24.4",
3
+ "version": "1.24.5",
4
4
  "description": "AI-powered issue solver and hive mind for collaborative problem solving",
5
5
  "main": "src/hive.mjs",
6
6
  "type": "module",
@@ -724,6 +724,48 @@ export const calculateSessionTokens = async (sessionId, tempDir) => {
724
724
  throw new Error(`Failed to read session file: ${readError.message}`);
725
725
  }
726
726
  };
727
+ /**
728
+ * Determines whether a stderr message line should be treated as an error.
729
+ *
730
+ * Excludes:
731
+ * - Emoji-prefixed warnings (Issue #477): lines starting with ⚠️ or ⚠
732
+ * - JSON-structured log messages with non-error level (Issue #1337):
733
+ * e.g. {"level":"warn","message":"...failed..."} — the word "failed" is in
734
+ * the message text but the level is "warn", so it is NOT an error.
735
+ * Only JSON lines with level "error" or "fatal" are treated as real errors.
736
+ *
737
+ * @param {string} message - A single trimmed stderr line
738
+ * @returns {boolean} true if the line should count as an error
739
+ */
740
+ export const isStderrError = message => {
741
+ const trimmed = message.trim();
742
+ if (!trimmed) return false;
743
+
744
+ // Detection 1: Emoji-prefixed warnings (Issue #477)
745
+ let isWarning = trimmed.startsWith('⚠️') || trimmed.startsWith('⚠');
746
+
747
+ // Detection 2: JSON-structured log messages (Issue #1337)
748
+ if (!isWarning && trimmed.startsWith('{')) {
749
+ try {
750
+ const parsed = JSON.parse(trimmed);
751
+ if (parsed && typeof parsed.level === 'string') {
752
+ const level = parsed.level.toLowerCase();
753
+ // Only "error" and "fatal" levels are real errors.
754
+ if (level !== 'error' && level !== 'fatal') {
755
+ isWarning = true;
756
+ }
757
+ }
758
+ } catch {
759
+ // Not valid JSON — fall through to keyword matching
760
+ }
761
+ }
762
+
763
+ if (!isWarning && (trimmed.includes('Error:') || trimmed.includes('error') || trimmed.includes('failed') || trimmed.includes('not found'))) {
764
+ return true;
765
+ }
766
+ return false;
767
+ };
768
+
727
769
  export const executeClaudeCommand = async params => {
728
770
  const {
729
771
  tempDir,
@@ -847,10 +889,17 @@ export const executeClaudeCommand = async params => {
847
889
  // Pass model for model-specific max output tokens (Issue #1221)
848
890
  // Pass thinkLevel and maxBudget for Opus 4.6 effort level conversion (Issue #1238)
849
891
  const claudeEnv = getClaudeEnv({ thinkingBudget: resolvedThinkingBudget, model: mappedModel, thinkLevel, maxBudget });
892
+ // Issue #1337: Enable ANTHROPIC_LOG=debug in --verbose mode to diagnose slow API requests.
893
+ // The BashTool pre-flight check suggests "Run with ANTHROPIC_LOG=debug to check for failed or slow API requests."
894
+ // When --verbose is enabled, we propagate ANTHROPIC_LOG=debug so users can see detailed API request info.
895
+ if (argv.verbose) {
896
+ claudeEnv.ANTHROPIC_LOG = 'debug';
897
+ }
850
898
  const modelMaxOutputTokens = getMaxOutputTokensForModel(mappedModel);
851
899
  if (argv.verbose) await log(`📊 CLAUDE_CODE_MAX_OUTPUT_TOKENS: ${modelMaxOutputTokens}`, { verbose: true });
852
900
  if (argv.verbose) await log(`📊 MCP_TIMEOUT: ${claudeCode.mcpTimeout}ms (server startup)`, { verbose: true });
853
901
  if (argv.verbose) await log(`📊 MCP_TOOL_TIMEOUT: ${claudeCode.mcpToolTimeout}ms (tool execution)`, { verbose: true });
902
+ if (argv.verbose) await log(`📊 ANTHROPIC_LOG: debug (verbose mode)`, { verbose: true });
854
903
  if (resolvedThinkingBudget !== undefined) await log(`📊 MAX_THINKING_TOKENS: ${resolvedThinkingBudget}`, { verbose: true });
855
904
  if (claudeEnv.CLAUDE_CODE_EFFORT_LEVEL) await log(`📊 CLAUDE_CODE_EFFORT_LEVEL: ${claudeEnv.CLAUDE_CODE_EFFORT_LEVEL}`, { verbose: true });
856
905
  if (!isNewVersion && thinkLevel) await log(`📊 Thinking level (via keywords): ${thinkLevel}`, { verbose: true });
@@ -1065,16 +1114,9 @@ export const executeClaudeCommand = async params => {
1065
1114
  // Log stderr immediately
1066
1115
  if (errorOutput) {
1067
1116
  await log(errorOutput, { stream: 'stderr' });
1068
- // Track stderr errors for failure detection
1069
- const trimmed = errorOutput.trim();
1070
- // Exclude warnings (messages starting with ⚠️) from being treated as errors
1071
- // Example: "⚠️ [BashTool] Pre-flight check is taking longer than expected. Run with ANTHROPIC_LOG=debug to check for failed or slow API requests."
1072
- // Even though this contains the word "failed", it's a warning, not an error
1073
- const isWarning = trimmed.startsWith('⚠️') || trimmed.startsWith('⚠');
1074
- // Issue #1165: Also detect "command not found" errors (e.g., "/bin/sh: 1: claude: not found")
1075
- // These indicate the Claude CLI is not installed or not in PATH
1076
- if (trimmed && !isWarning && (trimmed.includes('Error:') || trimmed.includes('error') || trimmed.includes('failed') || trimmed.includes('not found'))) {
1077
- stderrErrors.push(trimmed);
1117
+ // Track stderr errors for failure detection using shared helper (Issue #477, #1165, #1337)
1118
+ if (isStderrError(errorOutput)) {
1119
+ stderrErrors.push(errorOutput.trim());
1078
1120
  }
1079
1121
  }
1080
1122
  } else if (chunk.type === 'exit') {