@i-scope/mcp-server 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/LICENSE +21 -0
  3. package/README.md +373 -0
  4. package/dist/src/abi-check.d.ts +19 -0
  5. package/dist/src/abi-check.js +66 -0
  6. package/dist/src/bridge-driver.d.ts +90 -0
  7. package/dist/src/bridge-driver.js +290 -0
  8. package/dist/src/dap-client.d.ts +80 -0
  9. package/dist/src/dap-client.js +296 -0
  10. package/dist/src/dap-driver.d.ts +162 -0
  11. package/dist/src/dap-driver.js +703 -0
  12. package/dist/src/index.d.ts +3 -0
  13. package/dist/src/index.js +175 -0
  14. package/dist/src/state.d.ts +86 -0
  15. package/dist/src/state.js +15 -0
  16. package/dist/src/tools/abi-check.d.ts +3 -0
  17. package/dist/src/tools/abi-check.js +64 -0
  18. package/dist/src/tools/breakpoints.d.ts +3 -0
  19. package/dist/src/tools/breakpoints.js +56 -0
  20. package/dist/src/tools/execution.d.ts +3 -0
  21. package/dist/src/tools/execution.js +75 -0
  22. package/dist/src/tools/helpers.d.ts +27 -0
  23. package/dist/src/tools/helpers.js +134 -0
  24. package/dist/src/tools/inspection.d.ts +3 -0
  25. package/dist/src/tools/inspection.js +141 -0
  26. package/dist/src/tools/lifecycle.d.ts +3 -0
  27. package/dist/src/tools/lifecycle.js +103 -0
  28. package/dist/src/tools/preflight.d.ts +3 -0
  29. package/dist/src/tools/preflight.js +95 -0
  30. package/dist/src/tools/registry.d.ts +15 -0
  31. package/dist/src/tools/registry.js +19 -0
  32. package/dist/src/tools/snapshot.d.ts +3 -0
  33. package/dist/src/tools/snapshot.js +117 -0
  34. package/dist/src/tools/source-maps.d.ts +3 -0
  35. package/dist/src/tools/source-maps.js +232 -0
  36. package/dist/src/tools/sync.d.ts +3 -0
  37. package/dist/src/tools/sync.js +80 -0
  38. package/dist/src/tools/ui-modal.d.ts +3 -0
  39. package/dist/src/tools/ui-modal.js +182 -0
  40. package/package.json +73 -0
  41. package/src/abi-check.ts +97 -0
  42. package/src/bridge-driver.ts +328 -0
  43. package/src/dap-client.ts +336 -0
  44. package/src/dap-driver.ts +810 -0
  45. package/src/index.ts +155 -0
  46. package/src/state.ts +115 -0
  47. package/src/tools/abi-check.ts +66 -0
  48. package/src/tools/breakpoints.ts +59 -0
  49. package/src/tools/execution.ts +105 -0
  50. package/src/tools/helpers.ts +142 -0
  51. package/src/tools/inspection.ts +173 -0
  52. package/src/tools/lifecycle.ts +129 -0
  53. package/src/tools/preflight.ts +95 -0
  54. package/src/tools/registry.ts +34 -0
  55. package/src/tools/snapshot.ts +132 -0
  56. package/src/tools/source-maps.ts +222 -0
  57. package/src/tools/sync.ts +90 -0
  58. package/src/tools/ui-modal.ts +201 -0
@@ -0,0 +1,90 @@
1
+ import { type AbiPolicy, type PreflightCheckResponse, type UIModalClickRequest, type UIModalClickResponse, type UIModalDismissRequest, type UIModalDismissResponse, type UIModalFillRequest, type UIModalFillResponse, type UIModalListResponse } from '@i-scope/iscope-bridge-client';
2
+ import { type AbiCheckResult } from './abi-check.js';
3
+ export type { AbiCheckResult } from './abi-check.js';
4
+ export interface BridgeDriverOptions {
5
+ /** Explicit override; otherwise resolveHelperPath() runs. */
6
+ helperPath?: string;
7
+ /** Optional bundledRoot forwarded to resolveHelperPath. */
8
+ bundledRoot?: string;
9
+ /** Per-RPC timeout. Defaults to 10 000 ms. */
10
+ requestTimeoutMs?: number;
11
+ /** Diagnostic line sink (typically stderr writer). */
12
+ log?: (line: string) => void;
13
+ }
14
+ /**
15
+ * Lightweight wrapper around `IScopeBridge` that exposes the
16
+ * UI-modal-control + pre-flight surface to MCP tools. Spawns its own
17
+ * helper child on demand; safe to coexist with an active DAP session
18
+ * that also holds an iScopeBridge.exe.
19
+ */
20
+ export declare class BridgeDriver {
21
+ private readonly opts;
22
+ private bridge;
23
+ private spawned;
24
+ private initialized;
25
+ /**
26
+ * Single mutex protecting any in-flight transition (spawn or
27
+ * initialize). Non-null while a transition is running. Concurrent
28
+ * callers await the same promise instead of starting a second
29
+ * transition, which would race against the first (e.g. two spawn
30
+ * calls would leak a second helper child; a spawn racing an init
31
+ * could initialize a stale handle). `disconnect()` also awaits
32
+ * this so we never tear the helper down mid-transition.
33
+ */
34
+ private lifecyclePromise;
35
+ constructor(opts?: BridgeDriverOptions);
36
+ /**
37
+ * Ensure the helper child is spawned + its JSON-RPC loop alive.
38
+ * Does NOT call `initialize()`. Idempotent. Use this for the
39
+ * `preflight/check` path which is registry-only and must work on
40
+ * machines where Oscilloscope is not installed or not running.
41
+ */
42
+ private ensureSpawned;
43
+ /**
44
+ * Ensure the helper child is spawned AND `initialize()`d (i.e.
45
+ * connected to Oscilloscope's COM server). Idempotent. Calls
46
+ * `ensureSpawned()` internally so it works from a cold start AND
47
+ * from a warm state where `preflightCheck()` already spawned the
48
+ * helper.
49
+ */
50
+ private ensureReady;
51
+ /**
52
+ * Block until any in-flight `lifecyclePromise` resolves or rejects.
53
+ * Loops because a fresh transition may start while we await the
54
+ * current one (e.g. parallel callers chained through the mutex).
55
+ * Swallows rejections — the caller re-reads the boolean state and
56
+ * decides whether to retry. */
57
+ private awaitLifecycleSettled;
58
+ /** Install `promise` as the current `lifecyclePromise`, await it,
59
+ * and clear the slot on completion. The caller has already
60
+ * awaited the previous transition via `awaitLifecycleSettled()`,
61
+ * so installing here is race-free. */
62
+ private runTransition;
63
+ /** Construct an IScopeBridge with our standard wiring. Does NOT
64
+ * start the helper child — the caller decides between
65
+ * `start()` only (preflight path) and `start() + initialize()`
66
+ * (full ready path). */
67
+ private spawnHelper;
68
+ private log;
69
+ uiModalList(): Promise<UIModalListResponse>;
70
+ uiModalClick(args: UIModalClickRequest): Promise<UIModalClickResponse>;
71
+ uiModalFill(args: UIModalFillRequest): Promise<UIModalFillResponse>;
72
+ uiModalDismiss(args: UIModalDismissRequest): Promise<UIModalDismissResponse>;
73
+ preflightCheck(): Promise<PreflightCheckResponse>;
74
+ /** Wire ABI probe via `protocol/version` — no `initialize()`, no COM. */
75
+ abiCheck(policy?: AbiPolicy): Promise<AbiCheckResult>;
76
+ openFile(_path: string): Promise<void>;
77
+ getStatus(): Promise<{
78
+ status: number;
79
+ name: string;
80
+ }>;
81
+ runScript(_args: {
82
+ file: string;
83
+ mwfFile?: string;
84
+ }): Promise<void>;
85
+ /** Tear down the helper child. Idempotent. Resets state to `idle`.
86
+ * Waits for any in-flight transition (spawn or initialize) to
87
+ * settle first so we never `forceStop` a helper mid-handshake. */
88
+ disconnect(): Promise<void>;
89
+ }
90
+ //# sourceMappingURL=bridge-driver.d.ts.map
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ // BridgeDriver — direct (non-DAP) RPC access to iScopeBridge.exe.
3
+ //
4
+ // Live home of:
5
+ // - ui_modal_list / click / fill / dismiss (MCP UI plan)
6
+ // - system_preflight_check (Phase 1, MDM detection)
7
+ // - system_abi_check (wire ABI via protocol/version)
8
+ //
9
+ // Reserved for Phase 2/3 expansion:
10
+ // - control_open_file (BridgeDriver.openFile)
11
+ // - control_get_status (BridgeDriver.getStatus)
12
+ // - control_run_script (BridgeDriver.executeFile without debug)
13
+ // - control_close_application
14
+ // - data_* (TBD — needs helper-cpp extensions)
15
+ //
16
+ // Why a separate class from DapDriver:
17
+ // DapDriver OWNS a `debug-server.js` child which in turn owns its
18
+ // own iScopeBridge.exe (via `extension/.../com/bridge.ts`). For
19
+ // non-debug operations we don't want to pay the cost of a full DAP
20
+ // session — a direct helper child is plenty. The two drivers may
21
+ // coexist: COM lets multiple clients attach to Oscilloscope, so an
22
+ // AI agent can simultaneously hold a DAP session AND poll modal
23
+ // state via `ui_modal_list`.
24
+ //
25
+ // Lifecycle (two-stage state machine):
26
+ //
27
+ // ensureSpawned ensureReady
28
+ // ────────────► ────────────►
29
+ // 'idle' ─────────────► 'spawned' ──────────► 'ready'
30
+ // ▲ │ │
31
+ // │ disconnect() │ disconnect() │
32
+ // └──────────────────────┴─────────────────────┘
33
+ //
34
+ // - `ensureSpawned()` — guarantees the helper child is running and its
35
+ // stdio JSON-RPC loop is alive. Required for the `preflight/check`
36
+ // method which is registry-only and does NOT need a live COM
37
+ // connection (the MCP `system_preflight_check` tool runs even on a
38
+ // box where Oscilloscope is not installed).
39
+ // - `ensureReady()` — additionally guarantees `bridge.initialize()`
40
+ // has succeeded, i.e. the helper is connected to Oscilloscope's COM
41
+ // server. Required for every ui_modal_* method. Internally calls
42
+ // `ensureSpawned()` first so it works from a cold start AND from a
43
+ // warm state where preflight already spawned the helper.
44
+ // - `disconnect()` — full teardown. Resets state to `idle`.
45
+ //
46
+ // Both methods are idempotent and serialise concurrent callers via
47
+ // a single `lifecyclePromise` mutex — two parallel `ensureReady()`
48
+ // calls (one from a `ui_modal_list` tool, one from `ui_modal_click`
49
+ // chained right behind it) share the same spawn AND the same
50
+ // initialize. Failed transitions reset the relevant boolean so the
51
+ // next caller retries from the appropriate stage.
52
+ //
53
+ // `attachPolicy='attachOnly'` by default — we never auto-launch
54
+ // Oscilloscope just because the agent asked to list modals; if
55
+ // osc isn't running, `initialize()` returns connected=false and the
56
+ // calling tool surfaces a friendly "Oscilloscope is not running"
57
+ // error to the AI.
58
+ Object.defineProperty(exports, "__esModule", { value: true });
59
+ exports.BridgeDriver = void 0;
60
+ const iscope_bridge_client_1 = require("@i-scope/iscope-bridge-client");
61
+ const abi_check_js_1 = require("./abi-check.js");
62
+ /**
63
+ * Lightweight wrapper around `IScopeBridge` that exposes the
64
+ * UI-modal-control + pre-flight surface to MCP tools. Spawns its own
65
+ * helper child on demand; safe to coexist with an active DAP session
66
+ * that also holds an iScopeBridge.exe.
67
+ */
68
+ class BridgeDriver {
69
+ opts;
70
+ // ---- State-machine fields ------------------------------------------------
71
+ //
72
+ // Two booleans rather than a single discriminated enum because the
73
+ // transitions are linear (idle → spawned → ready) and we frequently
74
+ // need to ask "are we at-or-past stage X?" — booleans answer that
75
+ // in one read. Invariant: `initialized` implies `spawned`, which
76
+ // implies `bridge !== null`.
77
+ bridge = null;
78
+ spawned = false;
79
+ initialized = false;
80
+ /**
81
+ * Single mutex protecting any in-flight transition (spawn or
82
+ * initialize). Non-null while a transition is running. Concurrent
83
+ * callers await the same promise instead of starting a second
84
+ * transition, which would race against the first (e.g. two spawn
85
+ * calls would leak a second helper child; a spawn racing an init
86
+ * could initialize a stale handle). `disconnect()` also awaits
87
+ * this so we never tear the helper down mid-transition.
88
+ */
89
+ lifecyclePromise = null;
90
+ constructor(opts = {}) {
91
+ this.opts = opts;
92
+ }
93
+ /**
94
+ * Ensure the helper child is spawned + its JSON-RPC loop alive.
95
+ * Does NOT call `initialize()`. Idempotent. Use this for the
96
+ * `preflight/check` path which is registry-only and must work on
97
+ * machines where Oscilloscope is not installed or not running.
98
+ */
99
+ async ensureSpawned() {
100
+ // Wait until any in-flight transition (spawn or init) settles
101
+ // so our state read below is consistent.
102
+ await this.awaitLifecycleSettled();
103
+ if (this.spawned && this.bridge)
104
+ return this.bridge;
105
+ // Serialise the spawn behind the mutex so a parallel caller
106
+ // does not start a SECOND helper child. Re-check inside the
107
+ // critical section in case another caller spawned while we
108
+ // were queued.
109
+ const transition = (async () => {
110
+ if (this.spawned && this.bridge)
111
+ return;
112
+ const br = this.spawnHelper();
113
+ br.start();
114
+ this.bridge = br;
115
+ this.spawned = true;
116
+ })();
117
+ await this.runTransition(transition);
118
+ if (!this.bridge)
119
+ throw new Error('BridgeDriver spawn failed');
120
+ return this.bridge;
121
+ }
122
+ /**
123
+ * Ensure the helper child is spawned AND `initialize()`d (i.e.
124
+ * connected to Oscilloscope's COM server). Idempotent. Calls
125
+ * `ensureSpawned()` internally so it works from a cold start AND
126
+ * from a warm state where `preflightCheck()` already spawned the
127
+ * helper.
128
+ */
129
+ async ensureReady() {
130
+ const br = await this.ensureSpawned();
131
+ await this.awaitLifecycleSettled();
132
+ if (this.initialized && this.bridge)
133
+ return this.bridge;
134
+ // Serialise the initialize call behind the mutex. Failure
135
+ // leaves `spawned=true, initialized=false` so the next caller
136
+ // can retry the initialize step without re-spawning.
137
+ const transition = (async () => {
138
+ if (this.initialized && this.bridge)
139
+ return;
140
+ if (!this.spawned || !this.bridge) {
141
+ // disconnect() ran between ensureSpawned and the mutex
142
+ // becoming available. Surface a clear error so the
143
+ // caller knows to retry from scratch.
144
+ throw new Error('BridgeDriver: helper not spawned (lost race with disconnect)');
145
+ }
146
+ // autoLaunch=false: we never auto-spawn Oscilloscope from a
147
+ // UI tool. If osc is not running, `initialize` will throw
148
+ // (or return connected=false depending on helper config)
149
+ // and the calling tool surfaces a friendly "Oscilloscope
150
+ // is not running" error to the AI.
151
+ await this.bridge.initialize({ autoLaunch: false });
152
+ this.initialized = true;
153
+ })();
154
+ await this.runTransition(transition);
155
+ if (!this.bridge)
156
+ throw new Error('BridgeDriver init failed');
157
+ return br;
158
+ }
159
+ /**
160
+ * Block until any in-flight `lifecyclePromise` resolves or rejects.
161
+ * Loops because a fresh transition may start while we await the
162
+ * current one (e.g. parallel callers chained through the mutex).
163
+ * Swallows rejections — the caller re-reads the boolean state and
164
+ * decides whether to retry. */
165
+ async awaitLifecycleSettled() {
166
+ while (this.lifecyclePromise) {
167
+ const p = this.lifecyclePromise;
168
+ try {
169
+ await p;
170
+ }
171
+ catch {
172
+ /* let the caller re-inspect spawned/initialized */
173
+ }
174
+ if (this.lifecyclePromise === p)
175
+ this.lifecyclePromise = null;
176
+ }
177
+ }
178
+ /** Install `promise` as the current `lifecyclePromise`, await it,
179
+ * and clear the slot on completion. The caller has already
180
+ * awaited the previous transition via `awaitLifecycleSettled()`,
181
+ * so installing here is race-free. */
182
+ async runTransition(promise) {
183
+ // Guard form — never store a rejected promise in the slot.
184
+ // Without this, a concurrent `await this.lifecyclePromise`
185
+ // would synchronously re-throw the same rejection.
186
+ const guard = promise.then(() => { }, () => { });
187
+ this.lifecyclePromise = guard;
188
+ try {
189
+ await promise;
190
+ }
191
+ finally {
192
+ if (this.lifecyclePromise === guard)
193
+ this.lifecyclePromise = null;
194
+ }
195
+ }
196
+ /** Construct an IScopeBridge with our standard wiring. Does NOT
197
+ * start the helper child — the caller decides between
198
+ * `start()` only (preflight path) and `start() + initialize()`
199
+ * (full ready path). */
200
+ spawnHelper() {
201
+ const helperPath = this.opts.helperPath
202
+ ?? (0, iscope_bridge_client_1.resolveHelperPath)({ bundledRoot: this.opts.bundledRoot });
203
+ this.log(`[BridgeDriver] spawning helper: ${helperPath}`);
204
+ return new iscope_bridge_client_1.IScopeBridge({
205
+ helperPath,
206
+ requestTimeoutMs: this.opts.requestTimeoutMs ?? 10_000,
207
+ onStderr: (chunk) => this.log(`[helper-stderr] ${chunk.trimEnd()}`),
208
+ });
209
+ }
210
+ log(line) {
211
+ if (this.opts.log)
212
+ this.opts.log(line);
213
+ }
214
+ // ---- UI modal control ----------------------------------------------------
215
+ async uiModalList() {
216
+ const br = await this.ensureReady();
217
+ return br.uiModalList();
218
+ }
219
+ async uiModalClick(args) {
220
+ const br = await this.ensureReady();
221
+ return br.uiModalClick(args);
222
+ }
223
+ async uiModalFill(args) {
224
+ const br = await this.ensureReady();
225
+ return br.uiModalFill(args);
226
+ }
227
+ async uiModalDismiss(args) {
228
+ const br = await this.ensureReady();
229
+ return br.uiModalDismiss(args);
230
+ }
231
+ // ---- Pre-flight check (Phase 1, MDM detection) -------------------------
232
+ // Uses `ensureSpawned` rather than `ensureReady` because the C++
233
+ // `preflight/check` handler is registry-only and must work on a
234
+ // machine where Oscilloscope is not installed or not running.
235
+ // The state-machine contract guarantees that any subsequent
236
+ // `ui_modal_*` call from the same MCP server session will then
237
+ // promote the helper from `spawned` to `ready` via `ensureReady`,
238
+ // running `initialize()` exactly once — without this two-stage
239
+ // design, `preflightCheck` would set `bridge !== null` and a
240
+ // single-flag `ensureReady` would short-circuit, leaving the
241
+ // helper un-initialised when the first ui_modal_* call arrives
242
+ // (B1 regression, fixed 2026-05-19; see test 23-preflight-then-ui).
243
+ async preflightCheck() {
244
+ const br = await this.ensureSpawned();
245
+ return br.preflightCheck();
246
+ }
247
+ /** Wire ABI probe via `protocol/version` — no `initialize()`, no COM. */
248
+ async abiCheck(policy) {
249
+ const br = await this.ensureSpawned();
250
+ const version = await br.protocolVersion();
251
+ return (0, abi_check_js_1.evaluateAbiCheck)(version, policy ?? 'strict');
252
+ }
253
+ // ---- Phase 2/3 placeholders ---------------------------------------------
254
+ async openFile(_path) {
255
+ throw new Error('BridgeDriver.openFile not yet implemented (Phase 2)');
256
+ }
257
+ async getStatus() {
258
+ throw new Error('BridgeDriver.getStatus not yet implemented (Phase 2)');
259
+ }
260
+ async runScript(_args) {
261
+ throw new Error('BridgeDriver.runScript not yet implemented (Phase 2)');
262
+ }
263
+ // ---- Lifecycle -----------------------------------------------------------
264
+ /** Tear down the helper child. Idempotent. Resets state to `idle`.
265
+ * Waits for any in-flight transition (spawn or initialize) to
266
+ * settle first so we never `forceStop` a helper mid-handshake. */
267
+ async disconnect() {
268
+ await this.awaitLifecycleSettled();
269
+ const br = this.bridge;
270
+ this.bridge = null;
271
+ this.spawned = false;
272
+ this.initialized = false;
273
+ if (!br)
274
+ return;
275
+ try {
276
+ await br.shutdown({ closePolicy: 'ifWeLaunched' });
277
+ }
278
+ catch (e) {
279
+ this.log(`[BridgeDriver] shutdown error: ${e instanceof Error ? e.message : String(e)}`);
280
+ }
281
+ try {
282
+ br.forceStop();
283
+ }
284
+ catch {
285
+ /* helper might already be dead */
286
+ }
287
+ }
288
+ }
289
+ exports.BridgeDriver = BridgeDriver;
290
+ //# sourceMappingURL=bridge-driver.js.map
@@ -0,0 +1,80 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { DebugProtocol } from '@vscode/debugprotocol';
3
+ export interface DapClientOptions {
4
+ /** Runtime to spawn (typically 'node'). Defaults to 'node'. */
5
+ runtime?: string;
6
+ /** Absolute path to the .js / .cjs adapter entry point. */
7
+ executable: string;
8
+ /** Extra argv for the runtime, AFTER `executable`. Rarely used —
9
+ * DAP adapters typically take no argv. */
10
+ args?: string[];
11
+ /** Environment for the child. Defaults to `process.env`. */
12
+ env?: NodeJS.ProcessEnv;
13
+ /** Working directory for the child. */
14
+ cwd?: string;
15
+ /** Per-request default timeout. Defaults to 30 000 ms. */
16
+ defaultTimeoutMs?: number;
17
+ /** Inherit the child's stderr into the parent's stderr. true is
18
+ * the right default for production (we surface adapter logs).
19
+ * Set false in unit tests if the log noise bothers you. */
20
+ inheritStderr?: boolean;
21
+ /** Diagnostic logger. Defaults to no-op. */
22
+ log?: (line: string) => void;
23
+ }
24
+ /**
25
+ * Stand-alone DAP client. Inherits from EventEmitter for event
26
+ * subscription. Type-safe `request<T>` and `waitForEvent<T>` give
27
+ * callers the response body / event payload directly.
28
+ */
29
+ export declare class DapClient extends EventEmitter {
30
+ private readonly runtime;
31
+ private readonly executable;
32
+ private readonly args;
33
+ private readonly env;
34
+ private readonly cwd;
35
+ private readonly inheritStderr;
36
+ private readonly log;
37
+ private child;
38
+ private childExited;
39
+ /** Monotonic outgoing message id. DAP spec: `seq` is per-sender
40
+ * and increases by one per message; the OTHER side has its own
41
+ * `seq` axis we ignore. */
42
+ private nextSeq;
43
+ /** Accumulating stdout buffer. We pull complete frames out of
44
+ * it as they arrive. Type widened to ArrayBufferLike to match
45
+ * what `Buffer.concat` and `Buffer#subarray` return in
46
+ * @types/node 22+. */
47
+ private rxBuffer;
48
+ /** Once we see `Content-Length: N\r\n\r\n` we remember N here
49
+ * until we've consumed exactly N bytes of body. -1 = "still
50
+ * parsing the header". */
51
+ private rxContentLength;
52
+ /** seq → outstanding request. We never await a response by
53
+ * `command` alone — two simultaneous `stackTrace`s would
54
+ * collide. `seq` is the only safe key. */
55
+ private readonly pending;
56
+ defaultTimeoutMs: number;
57
+ constructor(opts: DapClientOptions);
58
+ /** Spawn the adapter child. Returns once `spawn()` has been
59
+ * called — the child may still be initialising. Callers
60
+ * immediately issue `request('initialize', ...)` and the DAP
61
+ * request/response framing handles the rest. */
62
+ start(): Promise<void>;
63
+ /** Send a request and resolve with `response.body`. Rejects on
64
+ * - timeout (after `timeoutMs ?? this.defaultTimeoutMs`),
65
+ * - protocol-level failure (`response.success === false`),
66
+ * - child process exit (the exit handler nukes pending). */
67
+ request<T = unknown>(command: string, args?: unknown, timeoutMs?: number): Promise<T>;
68
+ /** Resolve with the next event of the given name. Honours a
69
+ * timeout to avoid hanging on tests that never fire the event
70
+ * they expect. */
71
+ waitForEvent<T extends DebugProtocol.Event = DebugProtocol.Event>(name: string, timeoutMs?: number): Promise<T>;
72
+ /** Tear the child down. Graceful path: close stdin → child sees
73
+ * EOF → exits → we resolve. Fallback path: after `gracefulMs`,
74
+ * SIGTERM; after another second, SIGKILL. Either way the
75
+ * Promise always resolves; we never throw from cleanup. */
76
+ stop(gracefulMs?: number): Promise<void>;
77
+ private onStdoutChunk;
78
+ private dispatch;
79
+ }
80
+ //# sourceMappingURL=dap-client.d.ts.map