Summary
After #8726/#8738/#8739 (which fixed the earlier startup blockers), the natively-compiled Claude Code cli.js 2.1.112 bundle boots further but still throws at module init on nearly every command (only --version escapes via early exit):
Uncaught (in promise) TypeError: Class extends value does not have valid prototype property
Node runs the same bundle fine. This is the next layer in the cc-boot chain (each fix reveals the next; agents on #8715/#8730 flagged this would happen).
Throw sites
crates/perry-runtime/src/object/class_registry/parent_static.rs:186 and state.rs:758 — the runtime dynamic class-parent registration. state.rs:758 fires for class X extends <function-valued parent> (a closure) when class_parent_prototype_bits(closure_get_dynamic_prop(parent, "prototype")) returns None; parent_static.rs:186 fires on the bound-function branch when the read prototype isn't object-or-null.
What's ruled out
class X extends {PassThrough,Transform,Readable,Writable} (stream), class X extends EventEmitter, and the aliased form import {PassThrough as PT}; class X extends PT all work correctly on perry (byte-identical to node). So it's a MORE specific parent shape — likely another function-valued/aliased superclass whose .prototype perry doesn't expose, in the spirit of #8738 (which fixed the new <aliased-native> analog). Pinning the exact extends target needs instrumentation.
To pin (fast — runtime-only, so the codegen cache stays valid and re-link is ~49s)
Add a diagnostic at both throw sites printing the parent value's shape (is_closure_ptr? its name/prototype bits? whether it's a native-class registry entry?), rebuild the runtime staticlibs coherently, re-link the cached cli.js object, and run HOME=/tmp/cc_home cc-accept --help to capture the culprit. Then build a reduced synthetic (class X extends <that shape> {}) that reproduces, and fix so perry exposes a valid prototype for it (matching node).
Impact
Blocks booting the natively-compiled Claude Code bundle — layer 4 of the startup chain. Found while verifying #8726/#8738/#8739 against a freshly-built cc binary from origin/main.
Summary
After #8726/#8738/#8739 (which fixed the earlier startup blockers), the natively-compiled Claude Code cli.js 2.1.112 bundle boots further but still throws at module init on nearly every command (only
--versionescapes via early exit):Node runs the same bundle fine. This is the next layer in the cc-boot chain (each fix reveals the next; agents on #8715/#8730 flagged this would happen).
Throw sites
crates/perry-runtime/src/object/class_registry/parent_static.rs:186andstate.rs:758— the runtime dynamic class-parent registration.state.rs:758fires forclass X extends <function-valued parent>(a closure) whenclass_parent_prototype_bits(closure_get_dynamic_prop(parent, "prototype"))returns None;parent_static.rs:186fires on the bound-function branch when the readprototypeisn't object-or-null.What's ruled out
class X extends {PassThrough,Transform,Readable,Writable}(stream),class X extends EventEmitter, and the aliased formimport {PassThrough as PT}; class X extends PTall work correctly on perry (byte-identical to node). So it's a MORE specific parent shape — likely another function-valued/aliased superclass whose.prototypeperry doesn't expose, in the spirit of #8738 (which fixed thenew <aliased-native>analog). Pinning the exactextendstarget needs instrumentation.To pin (fast — runtime-only, so the codegen cache stays valid and re-link is ~49s)
Add a diagnostic at both throw sites printing the parent value's shape (is_closure_ptr? its
name/prototypebits? whether it's a native-class registry entry?), rebuild the runtime staticlibs coherently, re-link the cached cli.js object, and runHOME=/tmp/cc_home cc-accept --helpto capture the culprit. Then build a reduced synthetic (class X extends <that shape> {}) that reproduces, and fix so perry exposes a valid prototype for it (matching node).Impact
Blocks booting the natively-compiled Claude Code bundle — layer 4 of the startup chain. Found while verifying #8726/#8738/#8739 against a freshly-built cc binary from origin/main.