Skip to content

Commit 9be2c73

Browse files
rentziassCopilot
andauthored
Add DAP tracker and fix stopped-event replay timing
Two changes to debug the 'variables not auto-loading' issue: 1. Add a DebugAdapterTrackerFactory that logs every message between VS Code and the debug adapter in the GitHub Actions output channel. This will show the exact DAP flow when connecting and stepping. 2. Fix the stopped-event replay timing: buffer replay now triggers when the configurationDone *response* arrives from the runner (not when the request is sent), with a short delay to let VS Code finish processing the response before receiving the stopped event. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 21a5f1a commit 9be2c73

File tree

2 files changed

+62
-19
lines changed

2 files changed

+62
-19
lines changed

src/debugger/debugger.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from "vscode";
22
import {getSession} from "../auth/auth";
3-
import {log, logError} from "../log";
3+
import {log, logDebug, logError} from "../log";
44
import {validateTunnelUrl} from "./tunnelUrl";
55
import {WebSocketDapAdapter} from "./webSocketDapAdapter";
66

@@ -20,6 +20,11 @@ export function registerDebugger(context: vscode.ExtensionContext): void {
2020
vscode.debug.registerDebugAdapterDescriptorFactory(DEBUG_TYPE, new ActionsDebugAdapterFactory())
2121
);
2222

23+
// Register a tracker to log all DAP traffic for diagnostics.
24+
context.subscriptions.push(
25+
vscode.debug.registerDebugAdapterTrackerFactory(DEBUG_TYPE, new ActionsDebugTrackerFactory())
26+
);
27+
2328
// Register the connect command.
2429
context.subscriptions.push(
2530
vscode.commands.registerCommand("github-actions.debugger.connect", () => connectToDebugger())
@@ -113,3 +118,37 @@ class ActionsDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory
113118
return new vscode.DebugAdapterInlineImplementation(adapter);
114119
}
115120
}
121+
122+
// ── Debug adapter tracker (diagnostics) ──────────────────────────────
123+
124+
class ActionsDebugTrackerFactory implements vscode.DebugAdapterTrackerFactory {
125+
createDebugAdapterTracker(): vscode.DebugAdapterTracker {
126+
return {
127+
onWillReceiveMessage(message: unknown) {
128+
const m = message as Record<string, unknown>;
129+
logDebug(`[tracker] VS Code → DA: ${String(m.type)}${m.command ? `:${String(m.command)}` : ""} (seq ${String(m.seq)})`);
130+
},
131+
onDidSendMessage(message: unknown) {
132+
const m = message as Record<string, unknown>;
133+
const body = m.body as Record<string, unknown> | undefined;
134+
let detail = String(m.type);
135+
if (m.command) {
136+
detail += `:${String(m.command)}`;
137+
}
138+
if (m.event) {
139+
detail += `:${String(m.event)}`;
140+
}
141+
if (m.event === "stopped" && body) {
142+
detail += ` threadId=${String(body.threadId)} allThreadsStopped=${String(body.allThreadsStopped)}`;
143+
}
144+
logDebug(`[tracker] DA → VS Code: ${detail} (seq ${String(m.seq)})`);
145+
},
146+
onError(error: Error) {
147+
logError(error, "[tracker] DAP error");
148+
},
149+
onExit(code: number | undefined, signal: string | undefined) {
150+
log(`[tracker] DAP session exited: code=${String(code)} signal=${String(signal)}`);
151+
}
152+
};
153+
}
154+
}

src/debugger/webSocketDapAdapter.ts

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -102,20 +102,6 @@ export class WebSocketDapAdapter implements vscode.DebugAdapter {
102102
const json = JSON.stringify(message);
103103
logDebug(`→ DAP: ${describeDapMessage(message)}`);
104104
this._ws.send(json);
105-
106-
// Detect configurationDone and replay any stopped events the runner
107-
// sent before VS Code was ready to receive them.
108-
const m = message as Record<string, unknown>;
109-
if (m.command === "configurationDone" && m.type === "request") {
110-
this._configurationDone = true;
111-
if (this._pendingStoppedEvents.length > 0) {
112-
logDebug(`Replaying ${this._pendingStoppedEvents.length} buffered stopped event(s)`);
113-
for (const evt of this._pendingStoppedEvents) {
114-
this._onDidSendMessage.fire(evt);
115-
}
116-
this._pendingStoppedEvents = [];
117-
}
118-
}
119105
}
120106

121107
dispose(): void {
@@ -156,17 +142,35 @@ export class WebSocketDapAdapter implements vscode.DebugAdapter {
156142

157143
logDebug(`← DAP: ${describeDapMessage(message)}`);
158144

159-
// Buffer stopped events that arrive before configurationDone — the
160-
// runner re-sends the stopped event on connect (before the client
161-
// finishes the DAP handshake) and VS Code silently drops them.
145+
// Buffer stopped events that arrive before the configurationDone
146+
// response — the runner re-sends the stopped event on connect
147+
// (before the DAP handshake completes) and VS Code drops them.
162148
const m = message as Record<string, unknown>;
163149
if (m.type === "event" && m.event === "stopped" && !this._configurationDone) {
164-
logDebug("Buffering stopped event (configurationDone not yet sent)");
150+
logDebug("Buffering stopped event (configurationDone response not yet received)");
165151
this._pendingStoppedEvents.push(message);
166152
return;
167153
}
168154

169155
this._onDidSendMessage.fire(message);
156+
157+
// When the configurationDone response arrives from the runner,
158+
// replay any stopped events that were buffered during the
159+
// handshake. We use a short delay so VS Code finishes processing
160+
// the configurationDone response before receiving the event.
161+
if (m.type === "response" && m.command === "configurationDone") {
162+
this._configurationDone = true;
163+
if (this._pendingStoppedEvents.length > 0) {
164+
const events = this._pendingStoppedEvents;
165+
this._pendingStoppedEvents = [];
166+
logDebug(`Replaying ${events.length} buffered stopped event(s)`);
167+
setTimeout(() => {
168+
for (const evt of events) {
169+
this._onDidSendMessage.fire(evt);
170+
}
171+
}, 50);
172+
}
173+
}
170174
});
171175

172176
ws.on("close", (code: number, reason: Buffer) => {

0 commit comments

Comments
 (0)