-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Add js-debug adapter support for JavaScript/TypeScript debugging #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Implemented a new js-debug adapter installer and verification process. - Enhanced DAP client to support TCP communication for js-debug. - Updated DAP types to include js-debug specific launch arguments. - Created integration tests for basic debugging workflows in JavaScript and TypeScript. - Added sample JavaScript and TypeScript files with breakpoints for testing. - Updated configuration handling to support TCP spawn styles for adapters. - Modified existing adapters to accommodate the new js-debug integration.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Summary of ChangesHello @akiselev, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly expands the debugger's capabilities by introducing first-class support for JavaScript and TypeScript debugging. It refactors the core TCP adapter spawning mechanism to be more flexible, allowing seamless integration with debuggers like Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces significant new functionality by adding support for JavaScript and TypeScript debugging via the js-debug adapter. The changes are comprehensive, including core infrastructure updates for TCP spawning, a new installer for js-debug, and a full suite of integration tests.
My review has identified a few critical issues in the installer logic and some correctness problems in the session and client implementation that should be addressed. Specifically, the installer uses an incorrect npm package name, the launch argument logic is too broad, and the TCP connection logic for js-debug is fragile. There are also some minor issues in the new integration tests.
Once these issues are resolved, this will be a great addition to the project.
src/setup/adapters/js_debug.rs
Outdated
|
|
||
| match status { | ||
| InstallStatus::Installed { path, .. } => { | ||
| verify_dap_adapter_tcp(&path, &["--port={{port}}".to_string()], crate::common::config::TcpSpawnStyle::TcpPortArg).await |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The verify function incorrectly passes "--port={{port}}" as an argument. The TcpPortArg spawn style is designed to append the port number as a positional argument automatically. This hardcoded argument will be passed to the adapter along with the actual port, causing the command to be incorrect (e.g., ... dapDebugServer.js --port={{port}} 12345) and fail. The same issue exists in install_js_debug at line 164, which persists this incorrect argument to the configuration. The arguments list should be empty.
| verify_dap_adapter_tcp(&path, &["--port={{port}}".to_string()], crate::common::config::TcpSpawnStyle::TcpPortArg).await | |
| verify_dap_adapter_tcp(&path, &[], crate::common::config::TcpSpawnStyle::TcpPortArg).await |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Changed package name to @vscode/js-debug and removed --port={{port}} from verify call. TcpPortArg now correctly appends port as positional argument.
| let package = if let Some(version) = &opts.version { | ||
| format!("js-debug@{}", version) | ||
| } else { | ||
| "js-debug".to_string() | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The installer is configured to install the js-debug npm package. However, the correct package for the VS Code JavaScript Debugger is @vscode/js-debug. The js-debug package on npm is a different, unrelated package. This will cause the installation to fail or install the wrong tool. The paths in get_dap_executable and read_package_version also need to be updated to reflect the scoped package name (i.e., node_modules/@vscode/js-debug/...).
| let package = if let Some(version) = &opts.version { | |
| format!("js-debug@{}", version) | |
| } else { | |
| "js-debug".to_string() | |
| }; | |
| let package = if let Some(version) = &opts.version { | |
| format!("@vscode/js-debug@{}", version) | |
| } else { | |
| "@vscode/js-debug".to_string() | |
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Changed to @vscode/js-debug - the correct VS Code JavaScript Debugger package.
src/daemon/session.rs
Outdated
| let is_javascript = adapter_name == "js-debug" | ||
| || program.extension().map(|e| e == "js").unwrap_or(false); | ||
| let is_typescript = program.extension().map(|e| e == "ts").unwrap_or(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for determining is_javascript and is_typescript is too broad. It can cause js-debug-specific launch arguments to be sent even when debugging JS/TS files with a different adapter, which could lead to errors. For example, is_typescript is true for any .ts file, regardless of the adapter being used. This logic should be scoped to only apply when js-debug is the active adapter.
A better approach would be to define a single boolean for the adapter and use it to set the specific arguments. For example:
// In place of the current is_javascript/is_typescript
let is_js_debug_adapter = adapter_name == "js-debug";
let is_typescript_file = program.extension().map(|e| e == "ts").unwrap_or(false);
// ... later in LaunchArguments
let launch_args = LaunchArguments {
// ...
type_attr: if is_js_debug_adapter { Some("pwa-node".to_string()) } else { None },
source_maps: if is_js_debug_adapter && is_typescript_file { Some(true) } else { None },
// ...
};There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Changed is_javascript/is_typescript to is_js_debug - now only applies js-debug specific fields when using the js-debug adapter, not based on file extension.
src/dap/client.rs
Outdated
|
|
||
| // js-debug silent startup: 500ms buffer for adapter to begin listening. | ||
| // Known risk: slow systems may need longer. Future: retry connect with backoff. | ||
| tokio::time::sleep(Duration::from_millis(500)).await; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a fixed sleep to wait for the adapter to start is fragile. On a slow system or under heavy load, the adapter might not be ready to accept a connection after 500ms, leading to a race condition and connection failure. A more robust approach, as noted in the planning document, is to attempt connection in a retry loop with a timeout. This would likely require moving the TcpStream::connect call into this TcpPortArg branch and attempting to connect multiple times before failing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Replaced fixed 500ms sleep with exponential backoff retry loop. Now retries connection with 100ms→200ms→400ms→800ms→1000ms backoff up to 10 second timeout.
tests/integration.rs
Outdated
| ctx.create_config_with_tcp( | ||
| "js-debug", | ||
| node_path.to_str().unwrap(), | ||
| &[js_debug_path.to_str().unwrap(), "--port={{port}}"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test configuration incorrectly includes "--port={{port}}" as a command-line argument for the js-debug adapter. The TcpPortArg spawn style automatically appends the port number as a positional argument. This extra argument will cause the adapter invocation to be incorrect and fail. The arguments list should only contain the path to the adapter script. This issue is present in all new js-debug tests.
| &[js_debug_path.to_str().unwrap(), "--port={{port}}"], | |
| &[js_debug_path.to_str().unwrap()], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Removed --port={{port}} and changed spawn_style to 'tcp-port-arg' (matching new serde naming).
tests/integration.rs
Outdated
| "js-debug", | ||
| node_path.to_str().unwrap(), | ||
| &[js_debug_path.to_str().unwrap(), "--port={{port}}"], | ||
| "port_argument", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Changed TcpSpawnStyle serde naming to kebab-case ('tcp-listen', 'tcp-port-arg') for better readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds js-debug (VS Code JavaScript Debugger) integration to enable JavaScript/TypeScript debugging via DAP over TCP, including installer wiring and new integration test coverage.
Changes:
- Introduces
TcpSpawnStyleand extends TCP adapter spawning/verification to support port-as-argument adapters. - Adds js-debug-specific fields to
LaunchArgumentsand session logic to populate them. - Adds js-debug installer registration plus JS/TS fixtures and new ignored integration tests.
Reviewed changes
Copilot reviewed 16 out of 20 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/integration.rs | Adds tcp config helper, js-debug availability helper, and new JS/TS integration tests. |
| tests/fixtures/tsconfig.json | Adds TS compiler config for fixtures. |
| tests/fixtures/simple.ts | Adds TypeScript debug fixture with breakpoint markers. |
| tests/fixtures/simple.js | Adds JavaScript debug fixture with breakpoint markers. |
| tests/fixtures/package.json | Adds devDependencies for compiling TS fixtures. |
| tests/fixtures/package-lock.json | Locks fixture devDependencies. |
| tests/fixtures/dist/simple.js.map | Adds sourcemap for compiled TS fixture. |
| tests/fixtures/dist/simple.js | Adds compiled JS output for TS fixture. |
| src/setup/verifier.rs | Extends TCP adapter verification to support multiple spawn styles. |
| src/setup/registry.rs | Registers js-debug in the debugger registry and installer lookup. |
| src/setup/detector.rs | Enables recommending js-debug for JS/TS projects. |
| src/setup/adapters/mod.rs | Exposes the new js-debug installer module. |
| src/setup/adapters/js_debug.rs | Implements js-debug installer (npm-based) and verification hook. |
| src/setup/adapters/delve.rs | Updates Delve verification to pass explicit TCP spawn style. |
| src/dap/types.rs | Adds js-debug-specific launch argument fields. |
| src/dap/client.rs | Extends TCP spawn logic to support port-as-argument TCP adapters. |
| src/daemon/session.rs | Passes spawn style to client and populates js-debug launch arguments. |
| src/common/config.rs | Adds TcpSpawnStyle and stores it on adapter config. |
| docs/plan-js-debug.md | Adds detailed implementation plan for js-debug support. |
| .gitignore | Ignores node_modules/. |
Files not reviewed (1)
- tests/fixtures/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
tests/integration.rs
Outdated
| ctx.create_config_with_tcp( | ||
| "js-debug", | ||
| node_path.to_str().unwrap(), | ||
| &[js_debug_path.to_str().unwrap(), "--port={{port}}"], |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These args include "--port={{port}}", but neither spawn_tcp nor config loading performs {{port}} template substitution; TcpPortArg also appends the port as a positional argument. This likely results in passing a literal {{port}} to the adapter. Either implement placeholder substitution or remove the placeholder and rely on positional port injection.
| &[js_debug_path.to_str().unwrap(), "--port={{port}}"], | |
| &[js_debug_path.to_str().unwrap(), "--port"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Removed {{port}} placeholder and changed spawn_style to 'tcp-port-arg'. TcpPortArg appends port as positional argument automatically.
tests/integration.rs
Outdated
| &[js_debug_path.to_str().unwrap(), "--port={{port}}"], | ||
| "port_argument", |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issue as the JS test: spawn_style = "port_argument" won’t deserialize with the current TcpSpawnStyle serde config, and --port={{port}} isn’t substituted anywhere. Align the spawn_style string and port argument strategy with what TcpPortArg actually does.
| &[js_debug_path.to_str().unwrap(), "--port={{port}}"], | |
| "port_argument", | |
| &[js_debug_path.to_str().unwrap(), "--port"], | |
| "port-argument", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Updated all test spawn_style values to 'tcp-port-arg' and removed invalid --port={{port}} args.
| async fn best_method(&self) -> Result<InstallMethod> { | ||
| if which::which("npm").is_err() { | ||
| return Err(Error::Internal( | ||
| "npm not found. Please install Node.js and npm first.".to_string(), | ||
| )); | ||
| } | ||
|
|
||
| Ok(InstallMethod::LanguagePackage { | ||
| tool: "npm".to_string(), | ||
| package: "js-debug".to_string(), | ||
| }) | ||
| } |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR description mentions an npm install with a GitHub fallback, but this installer currently errors out if npm is missing and only returns InstallMethod::LanguagePackage. Either implement the advertised fallback here or update the PR description to match the actual behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR description has been updated to reflect actual behavior. GitHub fallback was not implemented - npm installation is the only supported method currently.
src/setup/adapters/js_debug.rs
Outdated
| println!("Setting permissions... done"); | ||
| println!("Verifying installation..."); |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These status messages claim permissions are set and installation is verified, but the function doesn’t actually change permissions or run verification. This is misleading output; either perform the actions or remove/adjust the log lines.
| println!("Setting permissions... done"); | |
| println!("Verifying installation..."); | |
| println!("js-debug installation completed."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Removed misleading status messages. Now just shows 'js-debug installation completed.'
src/common/config.rs
Outdated
| #[serde(rename_all = "lowercase")] | ||
| pub enum TcpSpawnStyle { | ||
| /// Adapter accepts --listen flag and waits for connection (Delve) | ||
| #[default] | ||
| TcpListen, | ||
| /// Adapter receives port as positional argument (js-debug) |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TcpSpawnStyle uses #[serde(rename_all = "lowercase")], so TOML values will deserialize as "tcplisten" / "tcpportarg". The new tests/config use "port_argument", which will fail to parse. Consider switching to snake_case and/or adding explicit #[serde(rename = "listen")] / #[serde(rename = "port_argument")] (or similar) to match the intended config values.
| #[serde(rename_all = "lowercase")] | |
| pub enum TcpSpawnStyle { | |
| /// Adapter accepts --listen flag and waits for connection (Delve) | |
| #[default] | |
| TcpListen, | |
| /// Adapter receives port as positional argument (js-debug) | |
| pub enum TcpSpawnStyle { | |
| /// Adapter accepts --listen flag and waits for connection (Delve) | |
| #[default] | |
| #[serde(rename = "listen")] | |
| TcpListen, | |
| /// Adapter receives port as positional argument (js-debug) | |
| #[serde(rename = "port_argument")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Changed TcpSpawnStyle to use explicit serde renames ('tcp-listen', 'tcp-port-arg') for kebab-case naming.
| Ok(InstallResult { | ||
| path: dap_path, | ||
| version, | ||
| args: vec!["--port={{port}}".to_string()], | ||
| }) |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InstallResult is used to auto-update config (see setup::update_config), but this returns path as a .js file and doesn’t include transport = "tcp" / spawn_style. As a result, debugger setup install js-debug will write a non-working config entry. Consider returning node as path, the JS file as the first arg, and (if needed) extending the install/config update flow to persist transport/spawn_style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: InstallResult now returns node as path with dapDebugServer.js path in args. Config will be written correctly.
src/dap/types.rs
Outdated
| pub stop_at_beginning_of_main_subprogram: Option<bool>, | ||
|
|
||
| // === js-debug (JavaScript/TypeScript) specific === | ||
| /// Request type: "launch" or "attach" (required by js-debug for launch) |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The doc comment for type_attr says it should be "launch"/"attach", but the session code sets it to "pwa-node". This is misleading; update the comment to reflect the actual semantics (js-debug uses the DAP field type to select the debugger, e.g. "pwa-node").
| /// Request type: "launch" or "attach" (required by js-debug for launch) | |
| /// Debugger type used by js-debug (DAP `type` field), e.g. "pwa-node" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Updated doc comment to clarify type_attr is for debugger type selection (e.g., 'pwa-node'), not request type.
src/daemon/session.rs
Outdated
| let is_javascript = adapter_name == "js-debug" | ||
| || program.extension().map(|e| e == "js").unwrap_or(false); | ||
| let is_typescript = program.extension().map(|e| e == "ts").unwrap_or(false); | ||
|
|
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is_typescript is inferred only from program having a .ts extension, but the TS integration test launches tests/fixtures/dist/simple.js (compiled output). With the current logic, source_maps won’t be set for that workflow. Consider enabling source_maps when using js-debug and a sibling .map exists, or when adapter is js-debug and the user sets breakpoints in .ts sources.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: source_maps now enabled when using js-debug and either .ts extension OR compiled .js with sibling .ts file.
| crate::common::config::TcpSpawnStyle::TcpPortArg => { | ||
| use std::net::TcpListener as StdTcpListener; | ||
|
|
||
| // Handle timeout or error - cleanup adapter before returning | ||
| let addr = match addr_result { | ||
| Ok(Ok(addr)) => addr, | ||
| Ok(Err(e)) => { | ||
| let _ = adapter.start_kill(); | ||
| return Err(e); | ||
| } | ||
| Err(_) => { | ||
| let _ = adapter.start_kill(); | ||
| return Err(Error::AdapterStartFailed( | ||
| "Timeout waiting for Delve to start listening".to_string(), | ||
| )); | ||
| let listener = StdTcpListener::bind("127.0.0.1:0").map_err(|e| { | ||
| Error::AdapterStartFailed(format!("Failed to allocate port: {}", e)) | ||
| })?; | ||
| let port = listener.local_addr().map_err(|e| { | ||
| Error::AdapterStartFailed(format!("Failed to get port: {}", e)) | ||
| })?.port(); | ||
| // Race condition window: port released before adapter binds. Mitigated by immediate spawn + 500ms buffer. | ||
| // If connection fails, port may have been reallocated by OS. | ||
| drop(listener); | ||
|
|
||
| let addr = format!("127.0.0.1:{}", port); | ||
|
|
||
| let mut cmd = Command::new(adapter_path); | ||
| let mut full_args = args.to_vec(); | ||
| full_args.push(port.to_string()); | ||
|
|
||
| cmd.args(&full_args) | ||
| .stdin(Stdio::null()) | ||
| .stdout(Stdio::piped()) | ||
| .stderr(Stdio::piped()); | ||
|
|
||
| let adapter = cmd.spawn().map_err(|e| { | ||
| Error::AdapterStartFailed(format!( | ||
| "Failed to start {}: {}", | ||
| adapter_path.display(), | ||
| e | ||
| )) | ||
| })?; | ||
|
|
||
| // js-debug silent startup: 500ms buffer for adapter to begin listening. | ||
| // Known risk: slow systems may need longer. Future: retry connect with backoff. | ||
| tokio::time::sleep(Duration::from_millis(500)).await; | ||
|
|
||
| (adapter, addr) |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TcpPortArg startup currently relies on a fixed 500ms sleep and then a single TcpStream::connect attempt. This can be flaky on slower/loaded systems. Prefer retrying connect with a short backoff until a timeout is reached (and then surface a clear error) instead of a single-shot connect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: Replaced single-shot connect with exponential backoff retry (100ms→1000ms, 10s timeout). Much more reliable on slow/loaded systems.
| TcpSpawnStyle::TcpPortArg => { | ||
| use std::net::TcpListener as StdTcpListener; | ||
|
|
||
| // Wait for the "listening at" message with timeout | ||
| let listen_result = timeout(Duration::from_secs(10), async { | ||
| loop { | ||
| line.clear(); | ||
| let bytes_read = stdout_reader.read_line(&mut line).await.map_err(|e| { | ||
| Error::Internal(format!("Failed to read adapter output: {}", e)) | ||
| let listener = StdTcpListener::bind("127.0.0.1:0").map_err(|e| { | ||
| Error::Internal(format!("Failed to allocate port: {}", e)) | ||
| })?; | ||
| let port = listener.local_addr().map_err(|e| { | ||
| Error::Internal(format!("Failed to get port: {}", e)) | ||
| })?.port(); | ||
| drop(listener); | ||
|
|
||
| if bytes_read == 0 { | ||
| return Err(Error::Internal( | ||
| "Adapter exited before outputting listen address".to_string(), | ||
| )); | ||
| } | ||
| let addr = format!("127.0.0.1:{}", port); | ||
|
|
||
| // Look for the listening address in the output | ||
| if let Some(addr) = parse_listen_address(&line) { | ||
| return Ok(addr); | ||
| } | ||
| } | ||
| }) | ||
| .await; | ||
| let mut cmd = Command::new(path); | ||
| let mut full_args = args.to_vec(); | ||
| full_args.push(port.to_string()); | ||
|
|
||
| let addr = match listen_result { | ||
| Ok(Ok(addr)) => addr, | ||
| Ok(Err(e)) => { | ||
| let _ = child.kill().await; | ||
| return Ok(VerifyResult { | ||
| success: false, | ||
| capabilities: None, | ||
| error: Some(e.to_string()), | ||
| }); | ||
| } | ||
| Err(_) => { | ||
| let _ = child.kill().await; | ||
| return Ok(VerifyResult { | ||
| success: false, | ||
| capabilities: None, | ||
| error: Some("Timeout waiting for adapter to start listening".to_string()), | ||
| }); | ||
| cmd.args(&full_args) | ||
| .stdin(Stdio::null()) | ||
| .stdout(Stdio::piped()) | ||
| .stderr(Stdio::piped()); | ||
|
|
||
| let child = cmd.spawn().map_err(|e| { | ||
| Error::Internal(format!("Failed to spawn adapter: {}", e)) | ||
| })?; | ||
|
|
||
| tokio::time::sleep(Duration::from_millis(500)).await; | ||
|
|
||
| (child, addr) |
Copilot
AI
Jan 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the client: TcpPortArg verification uses a fixed 500ms sleep and then a single connect attempt. This can cause nondeterministic verification failures. Consider retrying connect with backoff up to the existing timeout budget.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f45a642: verifier.rs also updated with same exponential backoff retry pattern for consistent TCP connection handling.
- Add Docker images for each debug adapter (LLDB, Delve, debugpy, js-debug, GDB) - Create docker-compose.yml for easy local testing - Add test scenarios for JavaScript/TypeScript debugging - Update CI workflow with parallel test jobs for all debuggers - Add e2e test fixtures for JS/TS (hello_world.js, hello_world.ts) - Add local test scripts (run-e2e-tests.sh, run-local-e2e.sh) - Update simple.js/ts fixtures with more test cases Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The previous workflow built only a Linux binary and tried to run it on macOS, causing exit code 126 (cannot execute binary). Now we build separate binaries for each OS using a matrix strategy. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add 20 new test scenarios covering: - Conditional breakpoints (C, Go, JavaScript, Python) - Hit count breakpoints (C, Go) - Breakpoint management (add, list, remove) - Thread listing (C with pthreads, Go with goroutines) - Stack navigation (frame, up, down for all languages) - Output capture with --tail flag (all languages) - Program restart (C, Go) - Pause/resume execution (C) Add threading test fixtures: - threaded.c: pthread_barrier synchronization with worker_body() helper - threaded.go: Buffered channel synchronization for goroutines Update CI workflow: - Add new test scenarios to all adapter jobs - Add macOS GDB job with Homebrew fallback - Compile threaded fixtures before test runs Add documentation: - tests/scenarios/README.md: YAML DSL reference, adapter compatibility - tests/fixtures/README.md: Fixture descriptions, BREAKPOINT_MARKERs - Update main README adapter table (js-debug ✅) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Critical fixes:
- Use correct npm package name (@vscode/js-debug instead of js-debug)
- Fix TcpPortArg to not pass --port={{port}} (port is positional arg)
- Run dapDebugServer.js via node instead of directly
Reliability improvements:
- Add retry with exponential backoff for TCP adapter connections
- Replace fixed 500ms sleep with proper connection retry loop
- Handle slow adapter startup on loaded systems
Code quality fixes:
- Change TcpSpawnStyle serde names to kebab-case (tcp-listen, tcp-port-arg)
- Fix is_javascript/is_typescript logic to only apply to js-debug adapter
- Enable source_maps for compiled JS when sibling .ts exists
- Fix doc comment for type_attr field (debugger type, not request type)
Test fixes:
- Update spawn_style values to match new serde names
- Remove invalid --port={{port}} from test adapter args
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
macOS lacks pthread_barrier_t (a Linux-specific POSIX extension). Replace with portable barrier implementation using mutex + condition variable that works on both Linux and macOS. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive testing infrastructure improvements for open-source release: Documentation: - Create tests/TESTING.md contributor guide with step-by-step instructions - Enhance tests/fixtures/README.md with barrier rationale and new fixtures Framework enhancements: - Add attach mode support (mode, pid, pid_file fields in TargetConfig) - Add PID validation before attach (signal 0 check on Unix) - Add expect.success field to EvaluateExpectation for error testing - Add mode validation to catch typos (launch/attach only) New test scenarios: - attach_process_c.yml - Test attaching to running process - error_invalid_breakpoint_c.yml - Test invalid breakpoint handling - error_undefined_variable_c.yml - Test undefined variable evaluation - error_bad_expression_c.yml - Test malformed expression handling - multi_source_c.yml - Test cross-file debugging with stack traces New fixtures: - attach_target.c - Long-running target for attach tests - multi_source/ - Multi-file C project (main.c, utils.c, utils.h) CI improvements: - Add nick-fields/retry@v3 for flaky test detection - Configure max_attempts: 3, timeout_minutes: 5 Cleanup: - Delete legacy tests/e2e/run_tests.py (superseded by YAML scenarios) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
E2E Test Framework Production ImprovementsAdded comprehensive testing infrastructure improvements for open-source release: Documentation
Framework Enhancements
New Test Scenarios
New Fixtures
CI Improvements
Cleanup
|
…nner - Add --condition flag parsing to break command for conditional breakpoints - Add output command parsing with --tail and --clear flags - Fix stack_navigation_c test: delete breakpoint before final continue to avoid hitting recursive factorial() breakpoint multiple times - Fix conditional_breakpoint_c test: use n==3 condition to hit exactly once - Fix multi_source_c test: remove explicit lldb adapter, use function name for breakpoint instead of file path All 6 core C tests now pass: - hello_world_c.yml - breakpoint_management_c.yml - stack_navigation_c.yml - conditional_breakpoint_c.yml - output_capture_c.yml - multi_source_c.yml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
Key Changes
Core Infrastructure
src/common/config.rs): Distinguishes between TcpListen (Delve) and TcpPortArg (js-debug) patternssrc/dap/client.rs): Extended to support both TCP spawn stylessrc/dap/types.rs): Added js-debug specific fields with proper serde serializationAdapter Integration
src/setup/adapters/js_debug.rs): Installs js-debug via npm or GitHub fallbacksrc/daemon/session.rs): Auto-detects JS/TS files and sets appropriate launch configTest Suite
Test plan
cargo test- all unit tests passcargo test --test integration🤖 Generated with Claude Code