Skip to content

readline: pass the history options in a record of their own, not on the input stream - #47361

Open
robobun wants to merge 3 commits into
mainfrom
robobun/4130be35/readline-history-options-off-input
Open

robobun wants to merge 3 commits into
mainfrom
robobun/4130be35/readline-history-options-off-input

Conversation

@robobun

@robobun robobun commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Fix

  • The constructor gives setupHistoryManager a null-prototype record of its own: the historyOptions hunk of readline: improve performance nodejs/node#64585.
  • $Node.ReadlineInput no longer extends the history options type, so a store on the stream is a type error.
  • Verified: test/js/node/readline/readline.node.test.ts runs one fixture on Bun and on Node.js v26.7.0 or later, and expects the same 18 rows. Bun 1.4.2 differs on 15. Also the 102 vendored test-readline-* and test-repl-* files.
  • Self-reviewed: 13 concerns raised, 11 addressed. Not taken: two ask for tooling around the Node.js version bump.

Background

  • setupHistoryManager(options) creates the ReplHistory of an Interface and reads the history options from options.
  • readline, readline/promises, FileHandle.readLines() and the REPL construct through InterfaceConstructor. One hunk covers them.
  • Considered the whole upstream commit (three more hunks, tuned on V8) and a record for positional createInterface(stream) too (Node.js reads the stream there).

Downsides

  • Options form: one more 48-byte object per call, and 728 to 938 more JIT instructions with GC off. With GC on the builds do not separate. The stream keeps 32 bytes less.
  • createInterface(stream) still throws for a stream whose own size is not a number, as on Node.js v26.12.1. Bun 1.3.14 accepted it.
Notes

Which Bun differs from which Node.js. Bun 1.4.0 to 1.4.4 report Node.js v26.3.0 and behave as it does (it has the same three stores). Main reports v26.12.1 since #46533 and still has the stores. Bun 1.3.14 kept the options in locals (src/js/node/readline.ts:1068-1087 at bun-v1.3.14). I found no issue for this in oven-sh/bun. For a built-in stream the effect is three more own properties, and nothing reads them back unless the positional form runs on the same stream later.

Runs, by binary. Node.js v26.12.1 is the official linux-x64 build. The six-row script is the one from the report.

Binary six-row script fixture rows that differ from Node.js v26.12.1 ssri stream-buffers
Bun 1.3.14 (0d9b296, release) 6 of 6 right older readline, not comparable verified input.size() = 2
Bun 1.4.2 (744846f, release) 0 of 6 right 15 of 18 EBADSIZE ... Found: NaN input.size is not a function
release build of main 11c3671 0 of 6 right 15 of 18 EBADSIZE ... Found: NaN input.size is not a function
release build of this change on 11c3671 6 of 6 right 0 of 18 verified input.size() = 2
Node.js v26.3.0 0 of 6 right 15 of 18 EBADSIZE ... Found: NaN input.size is not a function

ssri is 14.0.0 and stream-buffers is 3.0.3, both unmodified:

// ssri: a valid file read line by line
const input = fs.createReadStream(file).pipe(ssri.integrityStream({ integrity: ssri.fromData(fs.readFileSync(file)), size: 16 }));
for await (const line of readline.createInterface({ input })) console.log(line);

// stream-buffers
const input = new ReadableStreamBuffer();
const rl = readline.createInterface({ input });
input.put("a\n");
input.size();

readline.node.test.ts on the same binaries, with Node.js v26.12.1 first on PATH: Bun 1.4.2 and the release build of main fail the Bun case (15 rows) and pass the Node.js case. The debug and release builds of this change pass both (83 tests). The Node.js case is skipped when node is older than 26.7.0. After the rebase onto da867c6 the debug build passes both cases again, and so do the vendored files.

Not taken, on purpose.

With a terminal. terminal: true calls emitKeypressEvents, which stores two symbol-keyed decoders on the input, as in Node.js. So a terminal interface still adds own symbols, and a non-extensible input still throws there. This change is only about the history options.

Cost, measured. Release builds (bun run build:release) of main 11c3671 with and without the change, same machine. perf, valgrind and bloaty are not installed on it. Instruction counts come from a perf_event_open counter for PERF_COUNT_HW_INSTRUCTIONS in user mode, which is what perf stat -e instructions:u reads. Sizes come from size and wc -c.

  • History-option operations on the input (Proxy traps), options form: 3 sets + 7 gets → 0 + 0 (Node.js v26.12.1: 0 + 0). Positional form: 7 gets on all three.
  • GC cells per createInterface + close (BUN_JSC_useGC=0, 2000 calls, heapStats().objectTypeCounts): options form 51.175 → 52.175 (+1 Object of 48 bytes), positional form 50.175 → 50.175.
  • InterfaceConstructor bytecode: 318 → 324 instructions. new_object 0 → 1, call_ignore_result 19 → 20 (the __proto__: null key is a call to the @setPrototypeDirect host function), jnundefined_or_null 1 → 2 (the ??). put_by_id stays at 16: three now store into the record.
  • Instructions per createInterface({ input: new PassThrough() }).close(), as (I(n) - I(m)) / (n - m):
    • GC on, JIT on, n = 200k, m = 50k, 12 interleaved runs: options form median 15,834 (14,797 to 17,128) against 16,718 (14,982 to 17,899). Positional form 16,159 (15,597 to 17,378) against 15,729 (14,014 to 16,414). The spread is 8 percent and the builds do not separate.
    • GC off, synchronous JIT: options form 9,824 → 10,552 (+728) for n = 200k, m = 50k, and 8,237 → 9,175 (+938) for n = 600k, m = 300k. Positional form 10,020 → 10,019 and 8,513 → 8,516.
    • GC off, interpreter: options form 174,404 → 172,211 (-2,193). Positional form 171,800 → 171,858.
    • One object in isolation, FTL / DFG / baseline / interpreter: { __proto__: null, a, b, c } 436 / 376 / 559 / 959, plain { a, b, c } 68 / 37 / 220 / 556, Object.create(null) and three stores 77 / 41 / 333 / 761. The __proto__: null key costs about 340 to 400 instructions in every tier. src/js has 636 such literals.
  • Bytes kept on a PassThrough input after close: 113.6 → 81.1 (-32). Out-of-line property storage of the input, used/capacity after createInterface({ input }): PassThrough 6/8 → 3/4, Transform 11/16 → 8/8, fs.ReadStream 10/16 → 7/8, net.Socket 18/32 → 15/16, process.stdin 13/16 → 10/16. The storage is no longer reallocated.
  • require("node:readline"): 3,114 cells kept on both builds. Instructions 15,295,110 against 15,284,999, inside the run-to-run spread.
  • Built-in text internal/readline/interface.js: 35,279 → 35,324 bytes. Release binary: +45 bytes of text (size), same file size.
  • bun build --compile --aot of a program that makes 2,000 interfaces: 1,507,247 → 1,513,845 bytes of machine code (+6,598). The type change alone (against the same record with the old extends ReadlineHistoryOptions and no cast) resizes 0 of 2,341 functions, and the emitted built-in JS is byte-identical.
  • Typecheck of the built-in modules (bun src/codegen/check-types-of-modules.ts): 0 errors. With the three stores put back: 3 errors (TS2339). With the cast removed: 1 error (TS2345).

Other suites. On the release build of the change: readline_promises.node.test.ts (3), history-of-interface-and-repl.test.ts (1), getStringWidth.test.ts (3), pause_stdin_should_exit.test.ts (1), readline_never_unrefs.test.ts (1), stdin-pause-pty.test.ts (1), stdin_fell_asleep.test.ts (2), members-of-prototype-objects-for-any-receiver.test.ts (32), test/js/bun/repl/repl.test.ts (129), test/aot/methods-of-library-classes-nobody-calls.test.ts (8), and AOT_PROGRAMS=test/js/node/readline with test/aot/buns-own-tests-as-compiled-code (7). The fixture compiled with --aot prints the same 18 rows (with a real path in place of __filename, which a compiled executable does not have on disk). On the debug build: the 20 test-readline-*, 82 test-repl-* and test-tty-stdin-pipe.js vendored files, run as scripts/runner.node.ts runs them.

Self-review, not taken. Two notes ask for a check that lists the upstream commits that touched the ported files when the Node.js version is bumped. That is tooling for the bump and not part of this bug.

Where the test lives. The new case is in readline.node.test.ts and not in history-of-interface-and-repl.test.ts: the existing test in that file needs 4.3 to 5.0 s under a debug build and timed out in 2 of 5 runs here.


[human-review] gate passed · iteration 2 · 3 files touched

fails on main (without fix)
ASAN without fix: 1 failed, 1 skipped
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/pr_gate.xml" test/js/node/readline/readline.node.test.ts
bun test v1.4.4 (367d939d9)

test/js/node/readline/readline.node.test.ts:
(pass) CSI > should be defined [8.50ms]
(pass) CSI > should have all the correct clear sequences [5.93ms]
(pass) readline.clearScreenDown() > should put clear screen sequence into writable when called [65.34ms]
(pass) readline.clearScreenDown() > should throw on invalid callback [40.74ms]
(pass) readline.clearScreenDown() > should that clearScreenDown() does not throw on null or undefined stream [10.88ms]
(pass) readline.clearLine() > should clear to the left of cursor when given -1 as direction [4.64ms]
(pass) readline.clearLine() > should clear to the right of cursor when given 1 as direction [1.69ms]
(pass) readline.clearLine() > should clear whole line when given 0 as direction [2.15ms]
(pass) readline.clearLine() > should call callback after clearing line [3.46ms]
(pass) readline.clearLine() > should throw on an invalid callback [3.18ms]
(pass) readline.clearLine() > should not throw on null or undefined stream [4.2
... (truncated)

release without fix: 1 failed, 1 skipped
bun test v1.4.3-canary.1 (367d939d9)

test/js/node/readline/readline.node.test.ts:
(pass) CSI > should be defined [0.27ms]
(pass) CSI > should have all the correct clear sequences [0.34ms]
(pass) readline.clearScreenDown() > should put clear screen sequence into writable when called [1.20ms]
(pass) readline.clearScreenDown() > should throw on invalid callback [15.46ms]
(pass) readline.clearScreenDown() > should that clearScreenDown() does not throw on null or undefined stream [0.20ms]
(pass) readline.clearLine() > should clear to the left of cursor when given -1 as direction [0.12ms]
(pass) readline.clearLine() > should clear to the right of cursor when given 1 as direction [0.02ms]
(pass) readline.clearLine() > should clear whole line when given 0 as direction [0.01ms]
(pass) readline.clearLine() > should call callback after clearing line [0.04ms]
(pass) readline.clearLine() > should throw on an invalid callback [0.04ms]
(pass) readline.clearLine() > should not throw on null or undefined stream [0.06ms]
(pass) readline.moveCursor() > shouldn't write when moveCursor(0, 0) is called [0.44ms]
(pass) readline.moveCursor() > should throw on invalid callback [0.04ms]
(pa
... (truncated)
passes on PR (with fix)
ASAN with fix: 1 skipped
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/pr_gate.xml" test/js/node/readline/readline.node.test.ts
bun test v1.4.4 (367d939d9)

test/js/node/readline/readline.node.test.ts:
(pass) CSI > should be defined [6.86ms]
(pass) CSI > should have all the correct clear sequences [5.45ms]
(pass) readline.clearScreenDown() > should put clear screen sequence into writable when called [61.76ms]
(pass) readline.clearScreenDown() > should throw on invalid callback [4.78ms]
(pass) readline.clearScreenDown() > should that clearScreenDown() does not throw on null or undefined stream [8.49ms]
(pass) readline.clearLine() > should clear to the left of cursor when given -1 as direction [3.98ms]
(pass) readline.clearLine() > should clear to the right of cursor when given 1 as direction [1.61ms]
(pass) readline.clearLine() > should clear whole line when given 0 as direction [1.85ms]
(pass) readline.clearLine() > should call callback after clearing line [2.86ms]
(pass) readline.clearLine() > should throw on an invalid callback [2.81ms]
(pass) readline.clearLine() > should not throw on null or undefined stream [4.14m
... (truncated)

release with fix: 1 skipped
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped)
  target       linux-x64-gnu
  build type   Release
  build dir    ./build/release
  revision     74910a9745
  features     lto, baseline

21 deps, 432 codegen, 1228 objects in 1391ms

ninja: Entering directory `/workspace/bun/build/release'
[1/5] fetch rust-argon2
[rust-argon2] up to date
[2/5] fetch lolhtml
[lolhtml] up to date
[2/5] cargo plan → /workspace/bun/build/release/rust-target/plan.json
301 units: 203 lib, 32 custom-build (host), 28 run custom-build, 16 proc-macro (host), 17 lib (host), 4 run custom-build (host), 1 rlib
[4/5] fetch WebKit (prebuilt)
[WebKit] fetching https://github.com/oven-sh/WebKit/releases/download/autobuild-8c6c963e3c49fe39942d9625d1fc924128fad26e/bun-webkit-linux-amd64-lto-aot.tar.gz
[WebKit] extracted to /root/.bun/build-cache/webkit-8c6c963e3c49fe39-lto-aot (11.1s)
[4/5] reconfigure
[1/7] fetch WebKit (prebuilt)
[WebKit] up to date
[1/1622] rustc bun_output_tags 
[2/1622] rustc unicode_xid 
[3/1622] rustc unicode_ident 
[4/1622] rustc heck 
[5/1622] rustc fnv 
[6/1622] mkdir codegen
[7/1622] mkdir stamps
[8/1622] rustc ident_case 
[9/1622] rustc
... (truncated)
diff hotspot
src/js/internal/readline/interface.ts              |  17 ++-
 .../readline/history-options-off-input-fixture.cjs | 138 +++++++++++++++++++++
 test/js/node/readline/readline.node.test.ts        |  53 ++++++++
 3 files changed, 203 insertions(+), 5 deletions(-)

gate history · 1 passed · 0 rejected · iteration 2

evidence per changed file
file                                                      reads  edits  tests
src/js/internal/readline/interface.ts                         3      4     29
…/js/node/readline/history-options-off-input-fixture.cjs      2      6     33
test/js/node/readline/readline.node.test.ts                   5      4     29

`createInterface({ input })` stored `size`, `history` and
`removeHistoryDuplicates` on the input stream, then handed the stream to
`setupHistoryManager` as its options. The constructor now hands over a
null-prototype record of its own, as Node.js does since v26.7.0
(nodejs/node#64585). Without an options object the stream is still the
options, as in Node.js.

`$Node.ReadlineInput` no longer extends the history options, so a store
of a history option on an input stream is a type error.
@coderabbitai

coderabbitai Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between da867c6 and 9837463.

Files selected for processing: 3
  • src/js/internal/readline/interface.ts
  • test/js/node/readline/history-options-off-input-fixture.cjs
  • test/js/node/readline/readline.node.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

Walkthrough

The readline constructor now passes history settings separately from the input stream. A new fixture and cross-runtime test cover stream properties, interface history behavior, validation results, and errors.

Changes

Readline history options

Layer / File(s) Summary
Collect and pass history options
src/js/internal/readline/interface.ts
ReadlineHistoryOptions adds an optional __proto__?: null property, and ReadlineInput no longer extends it. The constructor collects history settings into a null-prototype options object and passes it to setupHistoryManager, falling back to the input stream when no options object is supplied.
Exercise history option behavior
test/js/node/readline/history-options-off-input-fixture.cjs, test/js/node/readline/readline.node.test.ts
The fixture records readline and REPL behavior, stream properties, validation results, and errors. The test compares its output under Bun and, when available, Node.js 26.7.0 or later.

Suggested reviewers: alii

Priority: Normal

Merge Risk: Minimal · up to 74910

Merge Risk: ⚪ Minimal · up to 74910

The change separates history settings from input streams while retaining positional-call compatibility. No actionable merge-blocking issue remains; merge after normal checks pass.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: passing readline history options in a separate record instead of storing them on the input stream.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The description follows the repository template. It has both required sections: "What does this PR do?" (as the Problem, Fix, and Background subsections) and "How did you verify your code works?" (as …
Full details: Description check

Explanation

The description follows the repository template. It has both required sections: "What does this PR do?" (as the Problem, Fix, and Background subsections) and "How did you verify your code works?" (as the Verified, Self-reviewed, and per-binary run tables). It states the bug clearly, names the upstream Node.js change it ports, and gives specific reproduction steps, test commands, and measured costs. Its main weakness is length and density: much of the verification detail sits in a collapsed Notes section, and the heading "What does this PR do?" is not used verbatim. These gaps are minor and do not hide the required information.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@robobun

robobun commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 11:46 AM PT - Oct 29th, 2026

❌ @robobun, your commit 74910a9 has 2 failures in Build #135239 (All Failures):

  • test/aot/build-scaling/build-scaling-2.test.ts - code 1 on 🍎 any aarch64
  • Failed to create agent for 🐧 aarch64-android - verify-baseline
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.0fe953eb-a2ce-4aa1-b51f-369bac6c8d2d
  • Failed to create agent for 🐧 3.23 x64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.8aa98862-d2f6-484c-a0db-959332ff8aa7
  • Failed to create agent for 🐧 3.23 x64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.a3eec87f-5fe4-4dc5-9840-840833530fbd
  • Failed to create agent for 🐧 3.23 x64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.abccf956-fd39-4853-8d90-b65e6dce414d
  • Failed to create agent for 🐧 3.23 x64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.5acb2cf5-a654-4626-a9ee-a8e8270ecc63
  • Failed to create agent for 🐧 3.23 x64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.99646846-49af-497b-9820-83d1183b3629
  • Failed to create agent for 🐧 3.23 x64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.79e337e8-0d84-4e21-8402-93298cd699aa
  • Failed to create agent for 🐧 3.23 aarch64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.824a7ae1-5f27-4be4-9c2e-ecea641cd0a5
  • Failed to create agent for 🐧 3.23 aarch64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.5aa4f02b-70e7-4552-8234-a78f0939f258
  • Failed to create agent for 🐧 3.23 aarch64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.6970c093-80dd-4727-8e06-4fbd6032feef
  • Failed to create agent for 🐧 3.23 aarch64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.7ca431df-75a7-4c91-b4e7-ca930c9b696f
  • Failed to create agent for 🐧 25.04 x64 - test-bun
  • CapacityLimitExceededThis account has reached its capacity limit. Reach out to your account team for assistance.af3aa904-4075-4baf-a401-9ed4abe125a8

🧪   To try this PR locally:

bunx bun-pr 47361

That installs a local version of the PR into your bun-47361 executable, so you can run:

bun-47361 --bun

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Beyond the inline findings on the test file, I also checked the other callers of setupHistoryManager: src/js/node/repl.ts:1134 already passes its own options record, and there is no ahead-of-time/ twin of internal/readline/interface.ts that would need the same hunk. The positional createInterface(stream) form still handing the stream itself to setupHistoryManager matches Node v26.12.1 interface.js#L226, so it is parity, not a regression.

Extended reasoning...

The runtime change is a four-line hunk in src/js/internal/readline/interface.ts that replaces three property stores on the user's input stream with a null-prototype historyOptions record, plus type declaration tweaks; it touches no security-sensitive surface. The two inline findings are both about the new test in test/js/node/readline/readline.node.test.ts (a per-test timeout override and a byte-exact stderr assertion against the system Node), not the runtime hunk, so a human should weigh them before merge.

@robobun

robobun commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status: ready for review. The diff is green on every platform that CI has. What is red in CI is CI infrastructure and one test that this change does not touch. A retry of those jobs needs a maintainer.

How I reproduced it. I ran the six-row script from the report and the new fixture (test/js/node/readline/history-options-off-input-fixture.cjs) on named binaries:

  • Bun 1.4.2 (744846f) and a release build of main (11c3671): 0 of 6 rows right. 15 of the 18 fixture rows differ from Node.js v26.12.1.
  • This branch and Node.js v26.12.1: 6 of 6 rows right. 0 fixture rows differ.

To run the test: bun bd test test/js/node/readline/readline.node.test.ts -t "should keep the history options off the input stream". The Node.js case runs when node on PATH is 26.7.0 or later.

CI.

  • Build 135171 (9837463): 180 jobs passed. That is every Linux and Windows test lane. One job failed before it ran a test: darwin 27 aarch64 - test-bun, with buildkite-agent artifact download timed out after 120s.
  • Build 135239 (74910a9, an empty commit to run CI again) is finished: 175 jobs passed, 1 failed, 12 got no agent.
    • readline.node.test.ts passed on debian 13 x64, debian 13 x64-asan, alpine 3.23 x64, Windows 2019 x64 and macOS aarch64 with 83 pass and 0 fail. The Bun case and the Node.js case both ran on each. On macOS x64 it passed with 82 pass and 1 skip: the Node.js case is skipped there because that host has a Node.js older than 26.7.0.
    • 12 jobs did not get an agent (Failed to create agent, EC2 CapacityLimitExceeded): linux aarch64-android - verify-baseline, 10 alpine test shards and 1 ubuntu 25.04 x64 test shard.
    • The failed job is a macOS aarch64 test job. It failed on test/aot/build-scaling/build-scaling-2.test.ts: twice as many functions cost 2.67 times the peakBytes; allowed: 2.5, on all 4 attempts. That test measures how the memory of the --aot compiler grows on a generated program. The program does not load node:readline, and this change does not touch the compiler. It is reported separately.

A warning that Node.js writes to stderr no longer fails the Node.js case.
A debug build gets 90 s for the new case, the time limit that
scripts/runner.node.ts gives each test.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — small, focused compat fix that matches upstream Node, and the follow-up commit addressed both earlier inline comments (Node-run stderr is no longer compared on a clean exit; the debug timeout no longer shrinks the CI runner's budget).

What was reviewed:

  • Traced the old path's three stream writes against ReplHistory's constructor reads: the new null-prototype record carries size/history/removeHistoryDuplicates; filePath/onHistoryFileLoaded are no longer picked up off the stream in the options form, and nothing else in src/js reads those keys back from the input.
  • Checked the legacy createInterface(stream, ...) form still hands the stream to setupHistoryManager, matching Node; repl.setupHistory passes its own options object and is unaffected.
  • Checked the test harness use: it.skipIf is valid on the node-harness it, nodeExeAtLeast already exists in test/harness.ts, pipes are drained concurrently and asserted as a combined object.
Extended reasoning...

The change touches one hunk of src/js/internal/readline/interface.ts (Bun's port of Node's readline Interface, shared by node:readline, readline/promises, repl and FileHandle.readLines), a new subprocess fixture, and one new test that compares the fixture's 18 rows between Bun and a system Node >= 26.7.0 when available. It touches no security-sensitive surface. The source diff is about ten lines with clear intent, the behavior is pinned empirically against real Node rather than only by description, both prior optional findings were addressed by the second commit, the bug hunt ran dry with no findings, and no CODEOWNERS entry covers these paths.

This branch has not been deployed

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants