From 70ed2a30bc8f2918a9a37a5207a0adf6ebc342ee Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Wed, 17 Jun 2026 19:28:48 -0700 Subject: [PATCH] debugger: lazily wait for initial break output Wait for the initial pause render before completing debugger REPL startup, but only when the initial pause is actually observed during startup initialization. Creating the wait promise before Runtime.runIfWaitingForDebugger() can hang when the debug target exits or disconnects without producing an initial pause event. It also assumes the inspector object always has parsed CLI options, which is not true for tests that use a minimal mock inspector. Create the initial-render wait lazily from the Debugger.paused handler while startup initialization is active. This preserves prompt ordering for normal initial breaks without blocking startup when no initial pause render occurs. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 --- lib/internal/debugger/inspect_repl.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/internal/debugger/inspect_repl.js b/lib/internal/debugger/inspect_repl.js index b6f8e32e806dfe..87388b41a47b2c 100644 --- a/lib/internal/debugger/inspect_repl.js +++ b/lib/internal/debugger/inspect_repl.js @@ -25,6 +25,7 @@ const { Promise, PromisePrototypeThen, PromiseResolve, + PromiseWithResolvers, ReflectGetOwnPropertyDescriptor, ReflectOwnKeys, RegExpPrototypeExec, @@ -380,6 +381,8 @@ function createRepl(inspector) { let selectedFrame; let exitDebugRepl; let contextLineNumber = 2; + let initialBreakRender; + let waitForInitialBreakRender = false; function resetOnStart() { knownScripts = {}; @@ -890,6 +893,13 @@ function createRepl(inspector) { }); } + function createInitialBreakRenderPromise(pauseRender) { + const { promise, resolve, reject } = PromiseWithResolvers(); + initialBreakRender = promise; + PromisePrototypeThen(pauseRender, resolve, reject); + return promise; + } + Debugger.on('paused', ({ callFrames, reason /* , hitBreakpoints */ }) => { if (process.env.NODE_INSPECT_RESUME_ON_START === '1' && reason === 'Break on start') { @@ -910,7 +920,7 @@ function createRepl(inspector) { const header = `${breakType} in ${scriptUrl}:${lineNumber + 1}`; - inspector.suspendReplWhile(() => + const pauseRender = inspector.suspendReplWhile(() => PromisePrototypeThen( SafePromiseAllReturnArrayLike([formatWatchers(true), selectedFrame.list(contextLineNumber)]), ({ 0: watcherList, 1: context }) => { @@ -919,6 +929,10 @@ function createRepl(inspector) { inspect(context); print(`${header}\n${breakContext}`); })); + + if (waitForInitialBreakRender && !initialBreakRender) { + createInitialBreakRenderPromise(pauseRender); + } }); function handleResumed() { @@ -1186,6 +1200,9 @@ function createRepl(inspector) { } async function initAfterStart() { + waitForInitialBreakRender = + !!inspector.options?.script && + process.env.NODE_INSPECT_RESUME_ON_START !== '1'; await Runtime.enable(); await Profiler.enable(); await Profiler.setSamplingInterval({ interval: 100 }); @@ -1194,7 +1211,12 @@ function createRepl(inspector) { await Debugger.setBlackboxPatterns({ patterns: [] }); await Debugger.setPauseOnExceptions({ state: pauseOnExceptionState }); await restoreBreakpoints(); - return Runtime.runIfWaitingForDebugger(); + await Runtime.runIfWaitingForDebugger(); + await PromiseResolve(); + waitForInitialBreakRender = false; + const initialBreakRenderPromise = initialBreakRender; + initialBreakRender = null; + await initialBreakRenderPromise; } return async function startRepl() {