fix(jupyter): make kernel ZMTP handshake compatible with libzmq (#34755)
The JS Jupyter kernel introduced in #34083 hand-rolls the ZMTP wire
protocol and got several details wrong that our own integration test
client tolerated but real libzmq peers (VSCode, JupyterLab,
jupyter_client) reject. As a result the kernel could not be used from
VSCode at all: selecting the Deno kernel spun and then failed with
"Failed to request kernel info", so no cells could run.
The decisive bug is the READY command framing. ZMTP (RFC 23) requires a
command body to begin with a one-octet command-name length, so READY
must go on the wire as 05 52 45 41 44 59. makeReadyCommand omitted that
length octet, so libzmq read the first byte ('R' = 0x52 = 82) as the
name length, ran off the end of the frame, declared the command
malformed, and tore down every channel before the handshake completed.
Two further deviations from what the previous libzmq-based kernel put on
the wire are corrected so a real ROUTER and our kernel agree:
The greeting hard-coded as-server=1 and a nonzero signature pad byte,
whereas libzmq uses as-server=0 with an all-zero pad for the symmetric
NULL mechanism. ROUTER replies also prepended the peer identity as a
wire frame; a real ROUTER keeps identity internal and sends frames
starting at the <IDS|MSG> delimiter, so that prepend is removed and the
frames are coalesced into a single write like libzmq does.
The integration test client carried the same malformed READY, which is
why the existing tests passed against a kernel that real clients cannot
talk to. It now sends a spec-compliant READY and, during the handshake,
asserts that the kernel's READY carries the name-length prefix, so a
regression back to the broken framing fails the suite.
Verified end to end against pyzmq (kernel_info_reply and execute_reply
ok) and zeromq.js, and confirmed working in VSCode.