You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit b7490aa
Browse filesBrowse the repository at this point in the historyBrowse files
fix(javascript): catch the first call of a first-declared function breakpoint and explain a late entry stop (#858)
js-debug's stopOnEntry breakpoint sits at line 0 col 0 and V8 resolves it
to the first breakable position in source order — the body of a function
declared above the first statement — so the "entry" stop is that
function's first call and recurs at every later call
(microsoft/vscode-js-debug#2430). The forced entry stop that binds a
pre-launch function breakpoint was that first call, auto-continued and
lost. The CDP bridge now reports an entry stop whose paused frame is the
function it just armed (matched by [[FunctionLocation]]) as the function
breakpoint, and annotates an entry stop that landed inside a function in
the stopped event's text; ChildSessionManager routes entry stops to the
bridge with nothing armed. The adapter's inert --inspect-brk=9229 append
and its --inspect promotion are removed (js-debug strips --inspect-brk
into stopOnEntry itself).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
**A JavaScript function breakpoint on the first-declared function no longer misses its first call, and a late entry stop says where it landed** — js-debug implements `stopOnEntry` with a breakpoint at line 1, column 1 that V8 resolves to the first breakable position in source order: for a file whose first declaration is a function the program calls later, that is the function's body, so the "entry" stop fires at the function's first call (after the top-level code before it ran) and again at every later call. The forced entry stop that binds a pre-launch function breakpoint was that very first call, and auto-continuing it lost the call for good with the breakpoint listed `verified: true`. The CDP bridge now recognises an entry stop whose paused frame is the function it just armed — matched by `[[FunctionLocation]]`, never by name — and reports it as the function breakpoint. A `stopOnEntry` launch that lands inside a function carries the explanation in the stop's `text` (`start_debugging`, `wait_for_stop`, `list_debug_sessions`): where it stopped, why, that the code before it has run, that later calls stop again, and what to do instead. The JavaScript adapter also stops appending `--inspect-brk=9229` to `runtimeArgs` for `stopOnEntry` and promoting a user's `--inspect` to `--inspect-brk` — js-debug strips `--inspect-brk` into `stopOnEntry` itself, so the first was inert and the second forced an entry stop nobody asked for. Reported upstream as microsoft/vscode-js-debug#2430 (#858)
Copy file name to clipboardExpand all lines: docs/javascript/README.md
+13Lines changed: 13 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -158,6 +158,19 @@ Both `dapLaunchArgs` and `adapterLaunchConfig` accept launch settings. When the
158
158
in both, `adapterLaunchConfig` wins, including `stopOnEntry`. Setting it to `true` keeps the target
159
159
paused at entry; `restart_debugging` replays that intent. An honoured `noDebug` disables the entry pause.
160
160
161
+
**Where the entry stop lands** (issue #858): js-debug implements `stopOnEntry` with a breakpoint at line 1,
162
+
column 1 of the program, and V8 resolves that to the first breakable position in *source* order. For a file
163
+
whose first declaration is a function that the program calls later, that position is inside the function —
164
+
so the "entry" stop fires at the function's first call, after the top-level code before it has run (output
165
+
included), and fires again at every later call. mcp-debugger cannot move the stop, but it says so: the
166
+
stop's `lastStop.text` (in the `start_debugging` answer, `wait_for_stop`, `list_debug_sessions`) explains
167
+
where it landed and why. To stop at the first statement, put a statement above the function or set a line
168
+
breakpoint on it. A function breakpoint on that first-declared function is not affected: the stop that
169
+
binds it *is* the function's first call, and it is reported as the function breakpoint. Reported upstream as
170
+
[vscode-js-debug#2430](https://github.com/microsoft/vscode-js-debug/issues/2430). Node's `--inspect-brk` is not an alternative: js-debug strips it from `runtimeArgs`
171
+
into `stopOnEntry`, so a bare `--inspect` or `--inspect-brk` in `adapterLaunchConfig.runtimeArgs` is
172
+
forwarded as given and changes nothing about the entry stop.
173
+
161
174
Use `envFile` to load dotenv values relative to the effective `cwd`, then override individual values
162
175
with `env`. A `null` value removes an inherited or file-defined variable:
-**Child-session architecture.** js-debug runs a parent session for launch orchestration and spawns a child session for the actual debuggee. This is invisible to you: the proxy routes evaluate/step/stack commands to the active context automatically. Never create a second MCP session for the "other" half.
71
-
-**Entry pause auto-continues.** With `stopOnEntry: false` (the default) the debugger automatically continues past entry breakpoints, so execution runs straight to your first breakpoint. A breakpoint reached as the program starts is in the `start_debugging` answer; one reached later — a route handler, a timer — leaves the launch answering `pending: true`, and `wait_for_stop` collects it. Set `dapLaunchArgs: { "stopOnEntry": true }` only when you want control at the first line.
71
+
-**Entry pause auto-continues.** With `stopOnEntry: false` (the default) the debugger automatically continues past entry breakpoints, so execution runs straight to your first breakpoint. A breakpoint reached as the program starts is in the `start_debugging` answer; one reached later — a route handler, a timer — leaves the launch answering `pending: true`, and `wait_for_stop` collects it. Set `dapLaunchArgs: { "stopOnEntry": true }` only when you want control at the first line — and read `lastStop.text` when you get it: for a file whose first declaration is a function the program calls later, js-debug's entry breakpoint resolves *inside that function*, so the "entry" stop is its first call (top-level code before it has already run) and every later call stops as "entry" again. The text says so; a line breakpoint on the first statement is the reliable way to stop there.
72
72
-**Stack filtering hides Node internals.**`get_stack_trace` returns user frames only by default; pass `includeInternals: true` if you genuinely need Node.js internal frames. If execution initially stops inside internals, just `continue_execution`.
73
73
-**TypeScript auto-detection.** Point `scriptPath` at the `.ts` file when `tsx`/`ts-node` is available. If neither is installed you get a warning (not an error) — fall back to the compiled `.js` with source maps.
74
74
-**Child processes are not auto-attached.**`autoAttachChildProcesses` defaults to `false`; pass it as `true` in `dapLaunchArgs` to debug `spawn`-ed Node children.
0 commit comments