fix(claude-print): accept the event-array envelope claude CLI 2.x emits - #493
Open
fedorovvvv wants to merge 1 commit into
Open
fedorovvvv wants to merge 1 commit into
fedorovvvv wants to merge 1 commit into
Conversation
`parse_envelope` decoded stdout as a bare `ClaudePrintResponse` object.
claude CLI 2.x returns `--output-format json` as a JSON *array* of stream
events whose final `{"type": "result", ...}` entry carries the envelope.
serde deserialises a JSON array into a struct positionally, so the first
event (`{"type": "system", "subtype": "init", ...}`) landed in `is_error`
and the decode failed with:
invalid type: map, expected a boolean at line 1 column 1
Both callers surface that as an auth problem — the `claude-code` LLM
provider appends "Is `claude` logged in? Try `claude login`." — so
`forgeplan reason` (and every Standard+ FPF ADI gate behind it) is dead
on a correctly configured, logged-in session, with remediation text
pointing at the wrong thing.
Unwrap the array to its last `type: "result"` event before decoding, and
keep the bare-object path for older CLI versions. An array with no result
event is a distinct, named error rather than a positional mis-parse of
some other event.
Tests: four unit tests over `parse_envelope` (array, bare object, in-band
error inside the array, array without a result event) plus an end-to-end
test through the mock-`claude` harness in the `claude-code` provider,
which is where the failure was reported.
Verified against claude CLI 2.1.266 and forgeplan 0.37.0: `forgeplan
reason RFC-001` fails on the released binary with the message above and
completes an ADI cycle on the patched one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YB7Md4NFwfDXiCcsy49PvX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #492.
The bug
claude --print --output-format jsonon claude CLI 2.x returns a JSON array of stream events, with the envelope as the final{"type": "result", ...}entry.parse_envelopedecoded stdout straight intoClaudePrintResponse, and serde deserialises a JSON array into a struct positionally — so the first event ({"type": "system", "subtype": "init", ...}) was fed tois_error: bool:Both callers report that as an authentication failure. The
claude-codeprovider appends "Isclaudelogged in? Tryclaude login.", so a correctly configured, logged-in session looks like a broken login, andforgeplan reason— with every Standard+ FPF ADI gate behind it — is dead.The change
parse_envelopenow parses stdout intoserde_json::Valuefirst and unwraps an array to its lasttype: "result"event before decoding. The bare-object path is untouched, so older CLI versions keep working — the array branch is additive.An array carrying no result event returns a named error rather than positionally mis-parsing some other event:
One function changed.
parse_envelopeispub(crate)with two consumers, so this fixes both theclaude-codeLLM provider (llm/mod.rs:247, the reported path) andplaybook::dispatch'sAgentDispatcher/PluginDispatcher(claude_print::invoke).Tests
Five added, all failing before the change:
parses_event_array_envelopeparses_bare_object_envelope_via_helperevent_array_preserves_in_band_erroris_error/api_error_statusread off the result event, not event 0event_array_without_result_event_errors_clearlyclaude_code_accepts_event_array_envelopeclaudeharnessThe existing fixtures could not have caught this:
json_response()andwrite_mock_claude()both emit the bare-object shape the CLI produced when #382 landed. The end-to-end test reuseswrite_mock_claudewith an array payload, so the harness now covers the shape real users hit.cargo fmt --checkclean,cargo clippy -p forgeplan-core --libclean,cargo test -p forgeplan-core --lib claude_print35 passed /llm::34 passed.Verified against the real CLI
forgeplan 0.37.0, claude CLI 2.1.266, macOS arm64 — same workspace, same artifact, same logged-in session:
Reproduced identically on 0.34.0, so this is not a 0.37.0 regression — it is the CLI's output shape moving out from under the parser.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YB7Md4NFwfDXiCcsy49PvX