Skip to content

Conversation

@zerone0x
Copy link
Contributor

@zerone0x zerone0x commented Jan 21, 2026

Summary

Fixes #112

The parse_json_response function in lib/response_analyzer.sh was failing when processing Claude Code CLI output because it assumed a single JSON object, but Claude CLI outputs a JSON array:

[
  {"type": "system", "subtype": "init", "session_id": "..."},
  {"type": "assistant", "message": {...}},
  {"type": "result", "subtype": "success", "result": "...", "is_error": false}
]

This caused Ralph to crash after Loop #1 with jq: invalid JSON text passed to --argjson.

Changes

  • Detect if JSON is an array before parsing using jq -e 'type == "array"'
  • Extract the "result" type message from the array (contains the actual completion data)
  • Preserve session_id from the init message for session continuity
  • Normalize to object format for existing parsing logic
  • Clean up temporary file after processing

Files Changed

  • lib/response_analyzer.sh - JSON array format detection and normalization (+30 lines)
  • tests/unit/test_json_parsing.bats - 8 new tests for array format handling (+158 lines)
  • CLAUDE.md - Documentation updates (version, test count, recent improvements)

Test Plan

  • All 318 tests passing (100% pass rate)
  • 8 new tests for JSON array format:
    • detect_output_format identifies JSON array as json
    • parse_json_response handles Claude CLI JSON array format
    • parse_json_response extracts session_id from Claude CLI array init message
    • parse_json_response handles empty array gracefully
    • parse_json_response handles array without result type message
    • parse_json_response extracts is_error from Claude CLI array result
    • analyze_response handles Claude CLI JSON array and extracts signals
    • analyze_response persists session_id from Claude CLI array format
  • Backward compatibility verified (existing tests still pass)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for Claude CLI JSON array format outputs with enhanced message extraction and session continuity handling
  • Tests

    • Expanded test coverage to 318 tests with comprehensive validation of JSON array format handling

✏️ Tip: You can customize this high-level summary in your review settings.

Claude Code CLI outputs a JSON array instead of a single object:
[{type: "system", ...}, {type: "assistant", ...}, {type: "result", ...}]

This caused parse_json_response to fail with "jq: invalid JSON text"
because it assumed the top-level JSON was an object.

Changes:
- Detect if JSON is an array before parsing
- Extract the "result" type message from the array
- Preserve session_id from init message for continuity
- Normalize to object format for existing parsing logic
- Clean up temporary file after processing

Fixes frankbria#112

Co-Authored-By: Claude <[email protected]>
@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2026

Walkthrough

This PR introduces support for Claude CLI JSON array output format in v0.10.1. It modifies the JSON parsing logic to detect array inputs, extract result objects, merge session IDs from init messages, and adds comprehensive test coverage for the new format handling.

Changes

Cohort / File(s) Summary
Documentation & Manifest
CLAUDE.md
Bumps version from v0.10.0 to v0.10.1, adds JSON Array Format Support section detailing array format detection, result extraction, session continuity preservation, and test count increase (310→318 tests).
Core JSON Parsing Logic
lib/response_analyzer.sh
Adds preliminary JSON validation, detects Claude CLI JSON array format, extracts the last "result" object from arrays, merges session_id from preceding "system init" messages into result objects using a temporary normalized file, and ensures proper cleanup.
JSON Array Format Test Suite
tests/unit/test_json_parsing.bats
Introduces 8 new tests covering JSON array detection, response parsing, session_id extraction from init messages, empty/malformed array handling, error detection, and integration scenarios with analyze_response and session persistence flows.

Sequence Diagram

sequenceDiagram
    participant Input as JSON Input<br/>(File)
    participant Validator as JSON Validator
    participant Detector as Format Detector
    participant Extractor as Array Handler
    participant Merger as Session ID Merger
    participant Parser as JSON Parser
    participant Output as Output<br/>(File)

    Input->>Validator: Pass input file
    Validator->>Validator: Validate JSON syntax
    
    alt Invalid JSON
        Validator->>Output: Error exit
    else Valid JSON
        Validator->>Detector: JSON is valid
        Detector->>Detector: Check if array or object
        
        alt Is JSON Array (Claude CLI format)
            Detector->>Extractor: Array detected
            Extractor->>Extractor: Extract "result" type object
            Extractor->>Merger: Pass extracted result
            Merger->>Merger: Query array for "system init"<br/>session_id
            
            alt Session ID found in init message
                Merger->>Merger: Create temp file with<br/>merged session_id
                Merger->>Parser: Use normalized temp file
            else No Session ID in init
                Merger->>Parser: Use extracted result
            end
        else Is JSON Object (Standard format)
            Detector->>Parser: Use original file
        end
        
        Parser->>Parser: Parse fields (status,<br/>metadata, result, etc.)
        Parser->>Output: Write parsed result
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • PR #47: Extends JSON parsing in lib/response_analyzer.sh with format detection logic and adds corresponding test coverage for Claude CLI output formats.
  • PR #62: Modifies parse_json_response to handle Claude CLI format with session_id extraction and management, which this PR builds upon for array format support.

Poem

🐰 Arrays hop through JSON fields so bright,
Session IDs merge in the pale moonlight,
Claude's format dances in bunny delight,
Tests multiply like carrots, all tidy and tight! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: handling Claude CLI JSON array output format in the analyzer, which directly addresses the core problem in the PR.
Linked Issues check ✅ Passed The PR successfully implements all objectives from issue #112: detects JSON arrays, extracts result elements, preserves session_id from init messages, normalizes data for existing logic, and prevents jq errors with comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly related to handling Claude CLI JSON array format: lib/response_analyzer.sh implements array detection and normalization, test_json_parsing.bats adds comprehensive tests, and CLAUDE.md documents the improvements.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Jan 21, 2026

Add JSON array support to bash:parse_json_response in response_analyzer.sh to handle Claude CLI output and preserve session_id

Extend bash:parse_json_response to normalize Claude CLI JSON array outputs by selecting the last type=="result" entry and merging session_id from the init message; update docs in CLAUDE.md and add array-format tests in test_json_parsing.bats.

📍Where to Start

Start with bash:parse_json_response in response_analyzer.sh.


📊 Macroscope summarized 5ce9bc8. 1 file reviewed, 2 issues evaluated, 1 issue filtered, 1 comment posted. View details


# Extract the "result" type message from the array (usually the last entry)
# This contains: result, session_id, is_error, duration_ms, etc.
local result_obj=$(jq '[.[] | select(.type == "result")] | .[-1] // {}' "$output_file" 2>/dev/null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If jq on line 85 fails, result_obj becomes empty and you then write invalid JSON. Consider guarding that result_obj is non-empty (default to {}) before echoing.

         local result_obj=$(jq '[.[] | select(.type == "result")] | .[-1] // {}' "$output_file" 2>/dev/null)
+        [[ -z "$result_obj" ]] && result_obj="{}"

🚀 Want me to fix this? Reply ex: "fix it for me".

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/response_analyzer.sh (1)

65-99: Prioritize result object's session_id field to prevent session ID loss during array normalization.

The normalization logic at lines 84–91 unconditionally injects the init message's session_id as sessionId, but never maps a result object's own session_id field (which per code comments contains "result, session_id, is_error, duration_ms, etc.") into the normalized sessionId field. Since parse_json_response later extracts only .sessionId // .metadata.session_id // "" and does not check for .session_id, arrays that lack an init message with session_id will lose the result's session ID, breaking session continuity.

🔧 Suggested fix
         # Build normalized object merging result with session_id
-        if [[ -n "$init_session_id" && "$init_session_id" != "null" ]]; then
-            echo "$result_obj" | jq --arg sid "$init_session_id" '. + {sessionId: $sid}' > "$normalized_file"
-        else
-            echo "$result_obj" > "$normalized_file"
-        fi
+        local effective_session_id
+        effective_session_id=$(echo "$result_obj" | jq -r '.sessionId // .session_id // empty' 2>/dev/null)
+        if [[ -z "$effective_session_id" ]]; then
+            effective_session_id="$init_session_id"
+        fi
+
+        if [[ -n "$effective_session_id" && "$effective_session_id" != "null" ]]; then
+            echo "$result_obj" | jq --arg sid "$effective_session_id" '. + {sessionId: $sid} | del(.session_id)' > "$normalized_file"
+        else
+            echo "$result_obj" | jq 'del(.session_id)' > "$normalized_file"
+        fi
🧹 Nitpick comments (1)
tests/unit/test_json_parsing.bats (1)

741-898: Add a regression case for arrays where only the result element carries the session id.

Current array tests cover init-derived session IDs, but not the variant where the result element includes session_id/sessionId and no init message. A small test would lock in the normalization behavior and prevent future regressions.

@frankbria frankbria merged commit 761db2f into frankbria:main Jan 22, 2026
7 of 9 checks passed
@frankbria
Copy link
Owner

Code review fixes applied during merge:

  1. Macroscope fix (line 85): Added guard against empty result_obj if jq fails

    [[ -z "$result_obj" ]] && result_obj="{}"
  2. CodeRabbit fix (lines 93-99): Prioritize result object's own session_id before falling back to init message - prevents session ID loss when arrays lack an init message

    local effective_session_id
    effective_session_id=$(echo "$result_obj" | jq -r '.sessionId // .session_id // empty' 2>/dev/null)
    if [[ -z "$effective_session_id" || "$effective_session_id" == "null" ]]; then
        effective_session_id="$init_session_id"
    fi
  3. CodeRabbit nitpick: Added regression test for arrays where only the result element carries session_id (no init message) - test feat: add dedicated uninstall.sh script #45

All 319 tests pass. Thanks for the contribution! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

parse_json_response fails with Claude Code CLI JSON array output format

2 participants