@basein/runner 0.2.12 → 0.3.1

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 (142) hide show
  1. package/README.md +540 -369
  2. package/dist/auth/client.d.ts +65 -3
  3. package/dist/auth/client.js +305 -53
  4. package/dist/bin/bir-hooks.d.ts +72 -31
  5. package/dist/bin/bir-hooks.js +176 -284
  6. package/dist/bin/bir-proxy.d.ts +17 -2
  7. package/dist/bin/bir-proxy.js +222 -28
  8. package/dist/bin/bir-scenario.d.ts +61 -21
  9. package/dist/bin/bir-scenario.js +593 -122
  10. package/dist/bin/bir.d.ts +12 -6
  11. package/dist/bin/bir.js +2935 -489
  12. package/dist/bin/investigate.js +40 -15
  13. package/dist/bin/scenario-edit.d.ts +7 -1
  14. package/dist/bin/scenario-edit.js +43 -21
  15. package/dist/bin/scenario-liveness.d.ts +194 -0
  16. package/dist/bin/scenario-liveness.js +459 -0
  17. package/dist/bin/scenario-stderr.d.ts +43 -0
  18. package/dist/bin/scenario-stderr.js +76 -0
  19. package/dist/bin/service-read.d.ts +88 -0
  20. package/dist/bin/service-read.js +128 -0
  21. package/dist/bin/setup.d.ts +19 -0
  22. package/dist/bin/setup.js +146 -20
  23. package/dist/config/adapters/claude-code.d.ts +92 -14
  24. package/dist/config/adapters/claude-code.js +291 -101
  25. package/dist/config/adapters/generic.d.ts +4 -1
  26. package/dist/config/adapters/generic.js +13 -14
  27. package/dist/config/generate.d.ts +392 -14
  28. package/dist/config/generate.js +666 -19
  29. package/dist/config/mcp-approval.d.ts +76 -0
  30. package/dist/config/mcp-approval.js +210 -0
  31. package/dist/config/node-path.d.ts +42 -0
  32. package/dist/config/node-path.js +102 -0
  33. package/dist/config/overrides.d.ts +62 -0
  34. package/dist/config/overrides.js +136 -0
  35. package/dist/config/resolve.d.ts +70 -8
  36. package/dist/config/resolve.js +186 -15
  37. package/dist/control/client.d.ts +22 -0
  38. package/dist/control/client.js +26 -7
  39. package/dist/control/correlation.d.ts +23 -5
  40. package/dist/control/correlation.js +0 -0
  41. package/dist/control/daemon.d.ts +400 -18
  42. package/dist/control/daemon.js +1105 -102
  43. package/dist/control/discovery.d.ts +77 -5
  44. package/dist/control/discovery.js +186 -11
  45. package/dist/control/ensure-hook.d.ts +61 -0
  46. package/dist/control/ensure-hook.js +160 -8
  47. package/dist/control/paths.d.ts +26 -0
  48. package/dist/control/paths.js +34 -0
  49. package/dist/control/pin-guard.d.ts +83 -0
  50. package/dist/control/pin-guard.js +534 -0
  51. package/dist/control/recorder-keeper.d.ts +229 -0
  52. package/dist/control/recorder-keeper.js +721 -0
  53. package/dist/control/recorder-main.d.ts +73 -0
  54. package/dist/control/recorder-main.js +778 -0
  55. package/dist/control/server.d.ts +707 -31
  56. package/dist/control/server.js +2787 -302
  57. package/dist/control/transcript.d.ts +21 -1
  58. package/dist/control/transcript.js +378 -112
  59. package/dist/index.d.ts +5 -1
  60. package/dist/index.js +5 -1
  61. package/dist/jsonrpc/framing.d.ts +76 -12
  62. package/dist/jsonrpc/framing.js +216 -59
  63. package/dist/proxy/intercept.d.ts +49 -5
  64. package/dist/proxy/intercept.js +188 -59
  65. package/dist/proxy/relay.d.ts +16 -0
  66. package/dist/proxy/relay.js +77 -5
  67. package/dist/proxy/revive.d.ts +122 -0
  68. package/dist/proxy/revive.js +251 -0
  69. package/dist/proxy/session.d.ts +222 -14
  70. package/dist/proxy/session.js +708 -99
  71. package/dist/record/recorder.d.ts +51 -3
  72. package/dist/record/recorder.js +3 -0
  73. package/dist/record/redact.d.ts +103 -9
  74. package/dist/record/redact.js +659 -30
  75. package/dist/record/remote-recorder.d.ts +327 -32
  76. package/dist/record/remote-recorder.js +1517 -187
  77. package/dist/record/switchable-recorder.d.ts +126 -0
  78. package/dist/record/switchable-recorder.js +351 -0
  79. package/dist/record/truncate.d.ts +40 -1
  80. package/dist/record/truncate.js +111 -4
  81. package/dist/replay/bash-channel.d.ts +35 -0
  82. package/dist/replay/bash-channel.js +133 -0
  83. package/dist/replay/bundle.d.ts +10 -0
  84. package/dist/replay/bundle.js +10 -0
  85. package/dist/replay/controller.d.ts +369 -20
  86. package/dist/replay/controller.js +1176 -107
  87. package/dist/replay/derive.d.ts +1 -0
  88. package/dist/replay/derive.js +81 -24
  89. package/dist/replay/executor.d.ts +51 -16
  90. package/dist/replay/executor.js +114 -41
  91. package/dist/replay/handover.d.ts +54 -1
  92. package/dist/replay/handover.js +55 -5
  93. package/dist/replay/logic.d.ts +62 -10
  94. package/dist/replay/logic.js +140 -22
  95. package/dist/replay/plan.d.ts +201 -27
  96. package/dist/replay/plan.js +581 -141
  97. package/dist/replay/safety.d.ts +72 -0
  98. package/dist/replay/safety.js +303 -0
  99. package/dist/replay/source-run.d.ts +10 -0
  100. package/dist/replay/source-run.js +80 -35
  101. package/dist/replay/targets.d.ts +15 -1
  102. package/dist/replay/targets.js +62 -4
  103. package/dist/replay/tool-error.d.ts +15 -1
  104. package/dist/replay/tool-error.js +33 -1
  105. package/dist/replay/types.d.ts +7 -4
  106. package/dist/upstream/client.d.ts +56 -3
  107. package/dist/upstream/client.js +61 -4
  108. package/dist/upstream/headers.d.ts +43 -0
  109. package/dist/upstream/headers.js +90 -0
  110. package/dist/upstream/http-client.d.ts +213 -22
  111. package/dist/upstream/http-client.js +1034 -168
  112. package/dist/upstream/http-transport.d.ts +143 -0
  113. package/dist/upstream/http-transport.js +391 -0
  114. package/dist/upstream/lazy-client.d.ts +8 -0
  115. package/dist/upstream/lazy-client.js +29 -1
  116. package/dist/upstream/sse.d.ts +78 -0
  117. package/dist/upstream/sse.js +189 -0
  118. package/dist/upstream/stdio-client.d.ts +61 -1
  119. package/dist/upstream/stdio-client.js +356 -33
  120. package/dist/util/atomic-write.d.ts +29 -0
  121. package/dist/util/atomic-write.js +96 -0
  122. package/dist/util/journal.d.ts +15 -0
  123. package/dist/util/journal.js +48 -3
  124. package/dist/util/log.d.ts +10 -0
  125. package/dist/util/log.js +28 -1
  126. package/dist/util/off-switch.d.ts +46 -0
  127. package/dist/util/off-switch.js +91 -0
  128. package/dist/util/service-health.d.ts +133 -0
  129. package/dist/util/service-health.js +217 -0
  130. package/docs/BaseInstRunner.md +694 -621
  131. package/docs/calculatedReplay.md +1625 -1304
  132. package/docs/calculatedReplayGuide.md +1212 -1087
  133. package/docs/installRun.md +1013 -772
  134. package/docs/loginWeb.md +627 -607
  135. package/docs/mcpmark.md +49 -16
  136. package/docs/my-first-sample.md +569 -545
  137. package/docs/quickstart.md +384 -311
  138. package/docs/t-bench.md +406 -394
  139. package/package.json +58 -57
  140. package/production.md +1371 -0
  141. package/scripts/install.ps1 +97 -6
  142. package/scripts/install.sh +104 -7
@@ -0,0 +1,78 @@
1
+ /**
2
+ * sse — a Server-Sent Events parser for the remote upstream (http-client.ts).
3
+ *
4
+ * WHY NOT THE OBVIOUS TEN LINES. The first version appended each chunk to one
5
+ * string and re-ran a blank-line regex over the whole buffer on every chunk.
6
+ * That is quadratic in the size of one event: a 24 MB tool result (a
7
+ * screenshot, a file) took 2.6 s to parse as SSE against 0.18 s as JSON, all of
8
+ * it added to the user's tool call. It also computed the separator length by
9
+ * guessing (`\r\n\n` ate the next event's first byte), never recognised a lone
10
+ * CR — which the SSE spec allows — so a CR-only server's answers never arrived,
11
+ * and it had no size bound at all.
12
+ *
13
+ * So this one is line-oriented and linear:
14
+ *
15
+ * - each chunk is scanned once, from where the last one stopped; a partial
16
+ * line is kept as a list of pieces and joined once, when its terminator
17
+ * arrives (a V8 `+=` rope would be flattened by every search);
18
+ * - CRLF, LF and lone CR all end a line, including a CRLF split across two
19
+ * chunks;
20
+ * - the fields are the spec's (`data`, `event`, `id`, `retry`, `:` comments),
21
+ * so a stream's last event id and retry hint are available to reconnects;
22
+ * - one event's data is capped (the framing layer's 32 MiB by default). Past
23
+ * it `push` returns false and the caller abandons the stream and answers the
24
+ * request it was carrying, rather than allocating until the process dies.
25
+ */
26
+ import type { Readable } from "node:stream";
27
+ export interface SseEvent {
28
+ /** The `event:` field; `"message"` when the event named none. */
29
+ event: string;
30
+ /** The `data:` lines joined with `\n`. */
31
+ data: string;
32
+ /** The stream's last event id at dispatch time, when it has one. */
33
+ id?: string;
34
+ }
35
+ /** Raised by {@link readSseStream} when one event outgrows the cap. */
36
+ export declare class SseTooLargeError extends Error {
37
+ constructor(limit: number);
38
+ }
39
+ export declare class SseParser {
40
+ /** The last `id:` seen. Per the spec it persists across events. */
41
+ lastEventId: string;
42
+ /** The server's `retry:` hint in ms, when it sent one. */
43
+ retryMs?: number;
44
+ private readonly onEvent;
45
+ private readonly maxEventChars;
46
+ /** The unterminated tail of the current line, in pieces (see the header). */
47
+ private partial;
48
+ private partialChars;
49
+ private dataLines;
50
+ private dataChars;
51
+ private eventType;
52
+ /** The previous chunk ended in CR: a leading LF on the next one is its pair. */
53
+ private pendingCr;
54
+ private overflowed;
55
+ /** Per instance: a shared global regex would share `lastIndex`. */
56
+ private readonly lineBreak;
57
+ constructor(onEvent: (event: SseEvent) => void, maxEventChars?: number);
58
+ /** True once an event outgrew the cap; the parser ignores input from then on. */
59
+ get tooLarge(): boolean;
60
+ /** Feed decoded text. Returns false once one event has outgrown the cap. */
61
+ push(text: string): boolean;
62
+ private overflow;
63
+ private line;
64
+ private dispatch;
65
+ }
66
+ /**
67
+ * Read an SSE body to its end, calling `onEvent` per complete event. Resolves
68
+ * when the stream ends cleanly; rejects when it errors (a reset, an abort) or
69
+ * with {@link SseTooLargeError} when one event outgrows the cap — the body is
70
+ * destroyed then, so the socket is released. An event handler that throws is
71
+ * isolated: one bad event must not end the stream carrying every other answer.
72
+ */
73
+ export declare function readSseStream(body: Readable, onEvent: (event: SseEvent) => void, opts?: {
74
+ maxEventBytes?: number;
75
+ parser?: (parser: SseParser) => void;
76
+ onHandlerError?: (err: unknown) => void;
77
+ }): Promise<void>;
78
+ //# sourceMappingURL=sse.d.ts.map
@@ -0,0 +1,189 @@
1
+ /**
2
+ * sse — a Server-Sent Events parser for the remote upstream (http-client.ts).
3
+ *
4
+ * WHY NOT THE OBVIOUS TEN LINES. The first version appended each chunk to one
5
+ * string and re-ran a blank-line regex over the whole buffer on every chunk.
6
+ * That is quadratic in the size of one event: a 24 MB tool result (a
7
+ * screenshot, a file) took 2.6 s to parse as SSE against 0.18 s as JSON, all of
8
+ * it added to the user's tool call. It also computed the separator length by
9
+ * guessing (`\r\n\n` ate the next event's first byte), never recognised a lone
10
+ * CR — which the SSE spec allows — so a CR-only server's answers never arrived,
11
+ * and it had no size bound at all.
12
+ *
13
+ * So this one is line-oriented and linear:
14
+ *
15
+ * - each chunk is scanned once, from where the last one stopped; a partial
16
+ * line is kept as a list of pieces and joined once, when its terminator
17
+ * arrives (a V8 `+=` rope would be flattened by every search);
18
+ * - CRLF, LF and lone CR all end a line, including a CRLF split across two
19
+ * chunks;
20
+ * - the fields are the spec's (`data`, `event`, `id`, `retry`, `:` comments),
21
+ * so a stream's last event id and retry hint are available to reconnects;
22
+ * - one event's data is capped (the framing layer's 32 MiB by default). Past
23
+ * it `push` returns false and the caller abandons the stream and answers the
24
+ * request it was carrying, rather than allocating until the process dies.
25
+ */
26
+ import { DEFAULT_MAX_LINE_BYTES } from "../jsonrpc/framing.js";
27
+ /** Raised by {@link readSseStream} when one event outgrows the cap. */
28
+ export class SseTooLargeError extends Error {
29
+ constructor(limit) {
30
+ super(`an event stream message exceeded ${limit} bytes`);
31
+ this.name = "SseTooLargeError";
32
+ }
33
+ }
34
+ export class SseParser {
35
+ /** The last `id:` seen. Per the spec it persists across events. */
36
+ lastEventId = "";
37
+ /** The server's `retry:` hint in ms, when it sent one. */
38
+ retryMs;
39
+ onEvent;
40
+ maxEventChars;
41
+ /** The unterminated tail of the current line, in pieces (see the header). */
42
+ partial = [];
43
+ partialChars = 0;
44
+ dataLines = [];
45
+ dataChars = 0;
46
+ eventType = "";
47
+ /** The previous chunk ended in CR: a leading LF on the next one is its pair. */
48
+ pendingCr = false;
49
+ overflowed = false;
50
+ /** Per instance: a shared global regex would share `lastIndex`. */
51
+ lineBreak = /\r\n|\r|\n/g;
52
+ constructor(onEvent, maxEventChars = DEFAULT_MAX_LINE_BYTES) {
53
+ this.onEvent = onEvent;
54
+ this.maxEventChars = maxEventChars;
55
+ }
56
+ /** True once an event outgrew the cap; the parser ignores input from then on. */
57
+ get tooLarge() {
58
+ return this.overflowed;
59
+ }
60
+ /** Feed decoded text. Returns false once one event has outgrown the cap. */
61
+ push(text) {
62
+ if (this.overflowed)
63
+ return false;
64
+ if (text.length === 0)
65
+ return true; // keep a pending CR for the next chunk
66
+ let start = 0;
67
+ if (this.pendingCr && text.charCodeAt(0) === 10)
68
+ start = 1;
69
+ this.pendingCr = false;
70
+ const lineBreak = this.lineBreak;
71
+ lineBreak.lastIndex = start;
72
+ let match;
73
+ while ((match = lineBreak.exec(text)) !== null) {
74
+ let line = text.slice(start, match.index);
75
+ if (this.partial.length > 0) {
76
+ this.partial.push(line);
77
+ line = this.partial.join("");
78
+ this.partial = [];
79
+ this.partialChars = 0;
80
+ }
81
+ start = match.index + match[0].length;
82
+ // A CR as the very last character may be the first half of a CRLF.
83
+ if (match[0] === "\r" && start === text.length)
84
+ this.pendingCr = true;
85
+ this.line(line);
86
+ if (this.overflowed)
87
+ return false;
88
+ }
89
+ if (start < text.length) {
90
+ const rest = text.slice(start);
91
+ this.partial.push(rest);
92
+ this.partialChars += rest.length;
93
+ }
94
+ if (this.dataChars + this.partialChars > this.maxEventChars) {
95
+ this.overflow();
96
+ return false;
97
+ }
98
+ return true;
99
+ }
100
+ overflow() {
101
+ this.overflowed = true;
102
+ this.partial = [];
103
+ this.dataLines = [];
104
+ }
105
+ line(line) {
106
+ if (line.length === 0) {
107
+ this.dispatch();
108
+ return;
109
+ }
110
+ if (line.charCodeAt(0) === 58 /* ":" */)
111
+ return; // a comment / keep-alive
112
+ const colon = line.indexOf(":");
113
+ let field;
114
+ let value;
115
+ if (colon === -1) {
116
+ field = line;
117
+ value = "";
118
+ }
119
+ else {
120
+ field = line.slice(0, colon);
121
+ value = line.slice(colon + 1);
122
+ if (value.charCodeAt(0) === 32 /* " " */)
123
+ value = value.slice(1);
124
+ }
125
+ switch (field) {
126
+ case "data":
127
+ this.dataLines.push(value);
128
+ this.dataChars += value.length + 1;
129
+ if (this.dataChars > this.maxEventChars)
130
+ this.overflow();
131
+ break;
132
+ case "event":
133
+ this.eventType = value;
134
+ break;
135
+ case "id":
136
+ if (!value.includes("\0"))
137
+ this.lastEventId = value;
138
+ break;
139
+ case "retry":
140
+ if (/^\d+$/.test(value))
141
+ this.retryMs = Number(value);
142
+ break;
143
+ default:
144
+ // Unknown fields are ignored, per the spec.
145
+ break;
146
+ }
147
+ }
148
+ dispatch() {
149
+ const event = this.eventType || "message";
150
+ this.eventType = "";
151
+ if (this.dataLines.length === 0)
152
+ return; // the spec: no data, no event
153
+ const data = this.dataLines.join("\n");
154
+ this.dataLines = [];
155
+ this.dataChars = 0;
156
+ this.onEvent(this.lastEventId ? { event, data, id: this.lastEventId } : { event, data });
157
+ }
158
+ }
159
+ /**
160
+ * Read an SSE body to its end, calling `onEvent` per complete event. Resolves
161
+ * when the stream ends cleanly; rejects when it errors (a reset, an abort) or
162
+ * with {@link SseTooLargeError} when one event outgrows the cap — the body is
163
+ * destroyed then, so the socket is released. An event handler that throws is
164
+ * isolated: one bad event must not end the stream carrying every other answer.
165
+ */
166
+ export async function readSseStream(body, onEvent, opts = {}) {
167
+ const limit = opts.maxEventBytes ?? DEFAULT_MAX_LINE_BYTES;
168
+ const parser = new SseParser((event) => {
169
+ try {
170
+ onEvent(event);
171
+ }
172
+ catch (err) {
173
+ opts.onHandlerError?.(err);
174
+ }
175
+ }, limit);
176
+ opts.parser?.(parser);
177
+ // Decoding with `stream: true` keeps a multi-byte character split across two
178
+ // chunks intact; the parser only ever sees whole characters.
179
+ const decoder = new TextDecoder("utf-8");
180
+ for await (const chunk of body) {
181
+ const text = typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
182
+ if (!parser.push(text)) {
183
+ body.destroy();
184
+ throw new SseTooLargeError(limit);
185
+ }
186
+ }
187
+ parser.push(decoder.decode());
188
+ }
189
+ //# sourceMappingURL=sse.js.map
@@ -14,8 +14,15 @@
14
14
  * mangles JSON), {@link resolveCommand} resolves the real file on PATH and,
15
15
  * for a batch file, invokes `cmd.exe /d /s /c` with `windowsVerbatimArguments`
16
16
  * and its own quoting.
17
+ *
18
+ * AND ONE THING THAT BREAKS THE USER'S MACHINE: a server the proxy started must
19
+ * not outlive it. On Windows a batch-file upstream is `cmd.exe` → `node` (or
20
+ * `python`, or Chrome), and killing `cmd.exe` leaves the rest running — holding
21
+ * a browser profile or a database lock the next session then cannot open. So
22
+ * {@link StdioUpstreamClient.shutdown} closes stdin first (the MCP-spec way to
23
+ * ask a server to exit), waits briefly, and only then kills the whole tree.
17
24
  */
18
- import type { JsonRpcMessage } from "../jsonrpc/types.js";
25
+ import { type JsonRpcMessage } from "../jsonrpc/types.js";
19
26
  import { BaseUpstreamClient } from "./client.js";
20
27
  export interface StdioUpstreamOptions {
21
28
  command: string;
@@ -26,6 +33,8 @@ export interface StdioUpstreamOptions {
26
33
  label?: string;
27
34
  /** Restart once with this backoff if the upstream dies unexpectedly. 0 disables. */
28
35
  restartDelayMs?: number;
36
+ /** Largest upstream line parsed. Defaults to the framing default; tests lower it. */
37
+ maxLineBytes?: number;
29
38
  }
30
39
  /** What `spawn` should actually be given for `command` on this platform. */
31
40
  export interface ResolvedCommand {
@@ -33,6 +42,37 @@ export interface ResolvedCommand {
33
42
  args: string[];
34
43
  windowsVerbatimArguments?: boolean;
35
44
  }
45
+ /** Default time a closing upstream gets to exit on stdin EOF before it is killed. */
46
+ export declare const DEFAULT_SHUTDOWN_GRACE_MS = 1500;
47
+ /**
48
+ * Quote one argument for `cmd.exe /c` and, behind it, the C runtime's argv
49
+ * parser in whatever the batch file launches.
50
+ *
51
+ * Three rules, each for a case that used to arrive mangled:
52
+ * - An embedded `"` becomes `""`, which cmd reads as leaving and re-entering
53
+ * a quoted run (so its metacharacters stay quoted) and the C runtime reads
54
+ * as one literal quote.
55
+ * - Backslashes before a quote — an embedded one or our closing one — are
56
+ * doubled, because the C runtime reads `\"` as an escaped quote.
57
+ * `C:\projects\` used to swallow the next argument whole.
58
+ * - `%` is taken *out* of the quotes and caret-escaped: cmd expands `%NAME%`
59
+ * even inside quotes, and a caret is literal there. Outside them, `^%`
60
+ * survives expansion (the text between the two percents is no longer a
61
+ * variable name, because it contains a quote) and the caret is removed
62
+ * afterwards, leaving `%`. The C runtime then joins the pieces:
63
+ * `"a"%"B"%"c"` is the single argument `a%B%c`.
64
+ */
65
+ export declare function quoteForCmd(arg: string): string;
66
+ /**
67
+ * Read an environment variable the way Windows does — case-insensitively.
68
+ *
69
+ * `process.env` is case-insensitive on Windows, but a *copy* of it (`{ ...process.env }`,
70
+ * which is what spawning with extra variables needs) is a plain object, and a
71
+ * normal Windows process spells the key `Path`. Reading `.PATH` off the copy
72
+ * found nothing, `npx` stayed unresolved, and every npx-launched server failed
73
+ * with `spawn npx ENOENT` whenever a host passed its environment through.
74
+ */
75
+ export declare function envValue(env: NodeJS.ProcessEnv, key: string): string | undefined;
36
76
  /** Find `command` on PATH, trying PATHEXT extensions. Returns undefined if absent. */
37
77
  export declare function whichSync(command: string, env?: NodeJS.ProcessEnv): string | undefined;
38
78
  /**
@@ -48,10 +88,30 @@ export declare class StdioUpstreamClient extends BaseUpstreamClient {
48
88
  private readonly opts;
49
89
  private restartsLeft;
50
90
  private closing;
91
+ /**
92
+ * Set while a `--restart` is in progress: host messages wait here for the
93
+ * new process to be spawned and re-initialised, instead of being written
94
+ * into a dead pipe and lost.
95
+ */
96
+ private restartBuffer?;
97
+ /** True while our replayed `initialize` is the one message allowed through. */
98
+ private handshaking;
99
+ /** The host's `initialize` params, replayed to a restarted upstream. */
100
+ private hostInitParams?;
101
+ private hostInitialized;
51
102
  constructor(opts: StdioUpstreamOptions);
52
103
  private start;
53
104
  private onChildGone;
105
+ /** Start a new process, replay the host's handshake to it, then release held messages. */
106
+ private restart;
54
107
  send(msg: JsonRpcMessage): void;
108
+ private write;
55
109
  close(): void;
110
+ /**
111
+ * Close the way the MCP spec asks a client to: end stdin, give the server
112
+ * `graceMs` to exit on its own, then kill it — with its whole process tree on
113
+ * Windows. A server that exits on EOF (nearly all do) costs no wait at all.
114
+ */
115
+ shutdown(graceMs?: number): Promise<void>;
56
116
  }
57
117
  //# sourceMappingURL=stdio-client.d.ts.map