fix(imessage): handle CLI child stdout/stderr stream errors#101401
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed July 7, 2026, 2:21 AM ET / 06:21 UTC. Summary PR surface: Source +40, Tests +117. Total +157 across 4 files. Reproducibility: no. live high-confidence reproduction was established in this review. The source-level reproduction path is clear: emit an Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Keep the narrow iMessage plugin fix, add redacted real-behavior proof for the stream-error path, and land after exact-head CI and review remain clean. Do we have a high-confidence way to reproduce the issue? No live high-confidence reproduction was established in this review. The source-level reproduction path is clear: emit an Is this the best way to solve the issue? Yes, this appears to be the narrow owner-boundary fix: handle stdout/stderr stream errors in both iMessage one-shot CLI helpers, mirroring the sibling RPC client. The safer alternative is not a new abstraction here; the main missing piece is real behavior proof. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 3175d8e7423d. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +40, Tests +117. Total +157 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
Merged via squash.
|
…#101401) * fix(imessage): handle CLI child stdout/stderr stream errors * fix(imessage): stop CLI children after stream failures --------- Co-authored-by: Peter Steinberger <[email protected]>
…#101401) * fix(imessage): handle CLI child stdout/stderr stream errors * fix(imessage): stop CLI children after stream failures --------- Co-authored-by: Peter Steinberger <[email protected]>
…#101401) * fix(imessage): handle CLI child stdout/stderr stream errors * fix(imessage): stop CLI children after stream failures --------- Co-authored-by: Peter Steinberger <[email protected]>
bindSignalCliOutput only subscribed to the 'data' event on signal-cli daemon stdout/stderr pipes. Unhandled 'error' events on those pipes crashed the agent runtime when the underlying fd broke (kill -9 on the daemon, pipe rupture, etc.). Mirror the imessage listenForIMessageCliStreamErrors pattern (PR openclaw#101401), but route the error through the daemon's error() callback instead of rejecting the spawn promise — the daemon is long-lived, and stream errors do not necessarily mean the process is dead. The existing child.on('error') and child.once('exit') handlers own process termination; stream errors just need to reach the log sink. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
bindSignalCliOutput only subscribed to the 'data' event on signal-cli daemon stdout/stderr pipes. Unhandled 'error' events on those pipes crashed the agent runtime when the underlying fd broke (kill -9 on the daemon, pipe rupture, etc.). Mirror the imessage listenForIMessageCliStreamErrors pattern (PR openclaw#101401), but route the error through the daemon's error() callback instead of rejecting the spawn promise — the daemon is long-lived, and stream errors do not necessarily mean the process is dead. The existing child.on('error') and child.once('exit') handlers own process termination; stream errors just need to reach the log sink. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
bindSignalCliOutput only subscribed to the 'data' event on signal-cli daemon stdout/stderr pipes. Unhandled 'error' events on those pipes crashed the agent runtime when the underlying fd broke (kill -9 on the daemon, pipe rupture, etc.). Mirror the imessage listenForIMessageCliStreamErrors pattern (PR openclaw#101401), but route the error through the daemon's error() callback instead of rejecting the spawn promise — the daemon is long-lived, and stream errors do not necessarily mean the process is dead. The existing child.on('error') and child.once('exit') handlers own process termination; stream errors just need to reach the log sink. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
What Problem This Solves
runIMessageCliJsonin bothactions.runtime.tsandsend.tsspawned animsgchild process and listened fordata, childerror, andcloseevents, but it did not attacherrorlisteners to the pipedstdoutandstderrstreams. If either stream emitted an error (for example, a broken pipe or EPIPE while the child was terminating), the error became an unhandled stream error and could crash the gateway worker.Why This Change Was Made
Node Readable streams can emit
errorindependently of the child processerrorevent. For transport code that runs inside the gateway process, unhandled stream errors are a reliability risk. Adding expliciterrorhandlers on bothchild.stdoutandchild.stderrlets the promise reject cleanly and gives operators a concrete error message instead of an unhandled exception.User Impact
imsgchild I/O.Evidence
errorevent handlers tochild.stdoutandchild.stderrin bothextensions/imessage/src/actions.runtime.tsandextensions/imessage/src/send.ts.extensions/imessage/src/actions.runtime.test.tsandextensions/imessage/src/send.test.tscovering stdout and stderr stream errors.