promigence 0.1.0-beta.12

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 (97) hide show
  1. package/NOTICE +14 -0
  2. package/README.md +88 -0
  3. package/dist/account.js +850 -0
  4. package/dist/agent.js +374 -0
  5. package/dist/argv.js +159 -0
  6. package/dist/bin.js +332 -0
  7. package/dist/bundle.js +133 -0
  8. package/dist/capacity.js +69 -0
  9. package/dist/commands.d.ts +110 -0
  10. package/dist/commands.js +2675 -0
  11. package/dist/connectreq.js +125 -0
  12. package/dist/credfile.js +188 -0
  13. package/dist/credits.js +197 -0
  14. package/dist/devcontainer.d.ts +99 -0
  15. package/dist/devcontainer.js +744 -0
  16. package/dist/device.js +129 -0
  17. package/dist/dirsnap.js +378 -0
  18. package/dist/errfix.js +262 -0
  19. package/dist/generated.d.ts +35 -0
  20. package/dist/generated.js +307 -0
  21. package/dist/github.js +307 -0
  22. package/dist/gitlab.js +210 -0
  23. package/dist/guide.d.ts +19 -0
  24. package/dist/guide.js +366 -0
  25. package/dist/handlers.js +511 -0
  26. package/dist/index.d.ts +14 -0
  27. package/dist/index.js +7 -0
  28. package/dist/init.d.ts +40 -0
  29. package/dist/init.js +352 -0
  30. package/dist/install.d.ts +23 -0
  31. package/dist/install.js +127 -0
  32. package/dist/io.d.ts +37 -0
  33. package/dist/io.js +318 -0
  34. package/dist/live.js +469 -0
  35. package/dist/login.js +1063 -0
  36. package/dist/mcp.js +889 -0
  37. package/dist/money.js +5 -0
  38. package/dist/orgs.js +475 -0
  39. package/dist/pricing.d.ts +52 -0
  40. package/dist/pricing.js +181 -0
  41. package/dist/report.js +132 -0
  42. package/dist/routes.js +135 -0
  43. package/dist/runners-github.js +257 -0
  44. package/dist/runners-gitlab.js +125 -0
  45. package/dist/runners-spec.js +137 -0
  46. package/dist/runners.js +1458 -0
  47. package/dist/sdk/blake3.d.ts +10 -0
  48. package/dist/sdk/blake3.js +111 -0
  49. package/dist/sdk/bundle.d.ts +96 -0
  50. package/dist/sdk/bundle.js +227 -0
  51. package/dist/sdk/ca-guard.js +166 -0
  52. package/dist/sdk/caller.d.ts +73 -0
  53. package/dist/sdk/caller.js +47 -0
  54. package/dist/sdk/client.d.ts +3015 -0
  55. package/dist/sdk/client.js +2583 -0
  56. package/dist/sdk/command-errors.d.ts +41 -0
  57. package/dist/sdk/command-errors.js +36 -0
  58. package/dist/sdk/context.d.ts +119 -0
  59. package/dist/sdk/context.js +588 -0
  60. package/dist/sdk/core.d.ts +285 -0
  61. package/dist/sdk/core.js +266 -0
  62. package/dist/sdk/credstore.d.ts +90 -0
  63. package/dist/sdk/credstore.js +206 -0
  64. package/dist/sdk/dispatcher.js +86 -0
  65. package/dist/sdk/github.d.ts +158 -0
  66. package/dist/sdk/github.js +78 -0
  67. package/dist/sdk/gitlab.d.ts +104 -0
  68. package/dist/sdk/gitlab.js +20 -0
  69. package/dist/sdk/handles.d.ts +82 -0
  70. package/dist/sdk/handles.js +135 -0
  71. package/dist/sdk/hint.js +7 -0
  72. package/dist/sdk/http2.js +1921 -0
  73. package/dist/sdk/index.d.ts +34 -0
  74. package/dist/sdk/index.js +15 -0
  75. package/dist/sdk/keyed.gen.js +7 -0
  76. package/dist/sdk/models.gen.d.ts +6162 -0
  77. package/dist/sdk/models.gen.js +1 -0
  78. package/dist/sdk/proxy.js +249 -0
  79. package/dist/sdk/pty.d.ts +171 -0
  80. package/dist/sdk/pty.js +496 -0
  81. package/dist/sdk/sandbox.d.ts +537 -0
  82. package/dist/sdk/sandbox.js +725 -0
  83. package/dist/sdk/ssh.d.ts +25 -0
  84. package/dist/sdk/ssh.js +114 -0
  85. package/dist/sdk/trace.js +80 -0
  86. package/dist/sdk/transport-worker.js +466 -0
  87. package/dist/sdk/warm.js +40 -0
  88. package/dist/ssh.js +267 -0
  89. package/dist/surface.d.ts +95 -0
  90. package/dist/surface.js +1452 -0
  91. package/dist/templates.js +53 -0
  92. package/dist/term.js +50 -0
  93. package/dist/timing.js +71 -0
  94. package/dist/untar.js +324 -0
  95. package/dist/uploadguard.js +75 -0
  96. package/llms.txt +209 -0
  97. package/package.json +52 -0
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,249 @@
1
+ import { request as httpRequest } from "node:http";
2
+ import { request as httpsRequest } from "node:https";
3
+ import { connect as tlsConnect } from "node:tls";
4
+ import { Readable } from "node:stream";
5
+ import { guardCertChain, makeCertChainGuard } from "./ca-guard.js";
6
+ function withCertGuard(existing) {
7
+ return existing === undefined ? guardCertChain : makeCertChainGuard(existing);
8
+ }
9
+ function envOf(env, name) {
10
+ const v = env[name] ?? env[name.toLowerCase()];
11
+ return v !== undefined && v.trim() !== "" ? v.trim() : undefined;
12
+ }
13
+ export const TRANSPORT_ENV = [
14
+ "HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy", "ALL_PROXY", "all_proxy", "PROMIGENCE_HTTP2", "NO_PROXY", "no_proxy",
15
+ ];
16
+ export function transportEnv(env = process.env) {
17
+ const view = {};
18
+ let proxied = false;
19
+ for (let i = 0; i < 6; i++) {
20
+ const k = TRANSPORT_ENV[i];
21
+ const v = env[k];
22
+ if (v === undefined)
23
+ continue;
24
+ view[k] = v;
25
+ proxied = true;
26
+ }
27
+ const h2 = env["PROMIGENCE_HTTP2"];
28
+ if (h2 !== undefined)
29
+ view["PROMIGENCE_HTTP2"] = h2;
30
+ if (proxied) {
31
+ const a = env["NO_PROXY"];
32
+ const b = env["no_proxy"];
33
+ if (a !== undefined)
34
+ view["NO_PROXY"] = a;
35
+ if (b !== undefined)
36
+ view["no_proxy"] = b;
37
+ }
38
+ return view;
39
+ }
40
+ export function noProxy(host, port, env = process.env) {
41
+ const list = envOf(env, "NO_PROXY");
42
+ if (!list)
43
+ return false;
44
+ const h = host.toLowerCase().replace(/^\[|\]$/g, "");
45
+ for (const raw of list.split(/[,\s]+/)) {
46
+ const entry = raw.trim().toLowerCase();
47
+ if (!entry)
48
+ continue;
49
+ if (entry === "*")
50
+ return true;
51
+ const [name, p] = entry.startsWith("[") ? [entry.replace(/\]:?.*$/, "").slice(1), entry.split("]:")[1]] : entry.split(":");
52
+ if (p && p !== port)
53
+ continue;
54
+ const bare = (name ?? "").replace(/^\*?\./, "");
55
+ if (h === bare || h.endsWith(`.${bare}`))
56
+ return true;
57
+ }
58
+ return false;
59
+ }
60
+ export function proxyFor(url, env = process.env) {
61
+ const https = envOf(env, "HTTPS_PROXY");
62
+ const http = envOf(env, "HTTP_PROXY");
63
+ const all = envOf(env, "ALL_PROXY");
64
+ if (https === undefined && http === undefined && all === undefined)
65
+ return undefined;
66
+ let u;
67
+ try {
68
+ u = new URL(url);
69
+ }
70
+ catch {
71
+ return undefined;
72
+ }
73
+ const port = u.port || (u.protocol === "https:" ? "443" : "80");
74
+ if (noProxy(u.hostname, port, env))
75
+ return undefined;
76
+ const raw = (u.protocol === "https:" ? https : http) ?? all;
77
+ if (!raw)
78
+ return undefined;
79
+ try {
80
+ const p = new URL(raw.includes("://") ? raw : `http://${raw}`);
81
+ if (p.protocol !== "http:" && p.protocol !== "https:")
82
+ return undefined;
83
+ return p;
84
+ }
85
+ catch {
86
+ return undefined;
87
+ }
88
+ }
89
+ function proxyAuth(p) {
90
+ if (!p.username)
91
+ return {};
92
+ const cred = `${decodeURIComponent(p.username)}:${decodeURIComponent(p.password)}`;
93
+ return { "proxy-authorization": `Basic ${Buffer.from(cred).toString("base64")}` };
94
+ }
95
+ function headersOf(init) {
96
+ const out = {};
97
+ const h = init?.headers;
98
+ if (!h)
99
+ return out;
100
+ if (h instanceof Headers)
101
+ h.forEach((v, k) => { out[k] = v; });
102
+ else if (Array.isArray(h))
103
+ for (const [k, v] of h)
104
+ out[k.toLowerCase()] = v;
105
+ else
106
+ for (const [k, v] of Object.entries(h))
107
+ out[k.toLowerCase()] = v;
108
+ return out;
109
+ }
110
+ async function bodyOf(init) {
111
+ const b = init?.body;
112
+ if (b === undefined || b === null)
113
+ return undefined;
114
+ if (typeof b === "string")
115
+ return Buffer.from(b);
116
+ if (b instanceof Uint8Array)
117
+ return Buffer.from(b.buffer, b.byteOffset, b.byteLength);
118
+ if (b instanceof ArrayBuffer)
119
+ return Buffer.from(b);
120
+ return Buffer.from(await new Response(b).arrayBuffer());
121
+ }
122
+ function toResponse(res) {
123
+ const headers = new Headers();
124
+ for (const [k, v] of Object.entries(res.headers)) {
125
+ if (v === undefined)
126
+ continue;
127
+ if (Array.isArray(v))
128
+ for (const x of v)
129
+ headers.append(k, x);
130
+ else
131
+ headers.set(k, String(v));
132
+ }
133
+ const status = res.statusCode ?? 502;
134
+ const noBody = status === 204 || status === 304;
135
+ return new Response(noBody ? null : Readable.toWeb(res), {
136
+ status, statusText: res.statusMessage ?? "", headers,
137
+ });
138
+ }
139
+ function abortError(signal) {
140
+ const r = signal.reason;
141
+ return r instanceof Error ? r : Object.assign(new Error("This operation was aborted"), { name: "AbortError" });
142
+ }
143
+ export function proxyFetch(proxy) {
144
+ const fetchViaProxy = async (input, init) => {
145
+ const url = new URL(typeof input === "string" ? input : input instanceof URL ? input.href : input.url);
146
+ const method = (init?.method ?? "GET").toUpperCase();
147
+ const headers = headersOf(init);
148
+ const body = await bodyOf(init);
149
+ if (body)
150
+ headers["content-length"] = String(body.length);
151
+ const signal = init?.signal ?? undefined;
152
+ if (signal?.aborted)
153
+ throw abortError(signal);
154
+ const proxyRequest = proxy.protocol === "https:" ? httpsRequest : httpRequest;
155
+ const proxyPort = Number(proxy.port || (proxy.protocol === "https:" ? 443 : 80));
156
+ return new Promise((resolve, reject) => {
157
+ let settled = false;
158
+ const fail = (e) => {
159
+ if (settled)
160
+ return;
161
+ settled = true;
162
+ const isAbort = e?.name === "AbortError" || e?.name === "TimeoutError";
163
+ reject(isAbort || e instanceof TypeError ? e : new TypeError("fetch failed", { cause: e }));
164
+ };
165
+ const onAbort = () => fail(abortError(signal));
166
+ signal?.addEventListener("abort", onAbort, { once: true });
167
+ const done = (res) => {
168
+ settled = true;
169
+ signal?.removeEventListener("abort", onAbort);
170
+ resolve(toResponse(res));
171
+ };
172
+ if (url.protocol === "http:") {
173
+ const req = proxyRequest({
174
+ host: proxy.hostname, port: proxyPort, method, path: url.href,
175
+ headers: { ...headers, host: url.host, ...proxyAuth(proxy) }, ...(signal ? { signal } : {}),
176
+ }, done);
177
+ req.on("error", fail);
178
+ req.end(body);
179
+ return;
180
+ }
181
+ const port = Number(url.port || 443);
182
+ const connect = proxyRequest({
183
+ host: proxy.hostname, port: proxyPort, method: "CONNECT", path: `${url.hostname}:${port}`,
184
+ headers: { host: `${url.hostname}:${port}`, ...proxyAuth(proxy) }, ...(signal ? { signal } : {}),
185
+ });
186
+ connect.on("error", fail);
187
+ connect.on("connect", (res, socket) => {
188
+ if (res.statusCode !== 200) {
189
+ socket.destroy();
190
+ fail(new TypeError(`fetch failed: the proxy ${proxy.host} refused CONNECT ${url.host} (HTTP ${res.statusCode})`));
191
+ return;
192
+ }
193
+ const tls = tlsConnect({ socket, servername: url.hostname, ALPNProtocols: ["http/1.1"], checkServerIdentity: guardCertChain });
194
+ tls.on("error", fail);
195
+ const req = httpsRequest({
196
+ host: url.hostname, port, method, path: `${url.pathname}${url.search}`,
197
+ headers: { ...headers, host: url.host }, createConnection: () => tls, agent: false,
198
+ ...(signal ? { signal } : {}),
199
+ }, done);
200
+ req.on("error", fail);
201
+ req.end(body);
202
+ });
203
+ connect.end();
204
+ });
205
+ };
206
+ return fetchViaProxy;
207
+ }
208
+ export function requestVia(url, options, env = process.env) {
209
+ const proxy = proxyFor(url.href, env);
210
+ const httpsOptions = (o) => {
211
+ if (url.protocol !== "https:")
212
+ return o;
213
+ const prev = o.checkServerIdentity;
214
+ return Object.assign({}, o, { checkServerIdentity: withCertGuard(prev) });
215
+ };
216
+ if (!proxy)
217
+ return (url.protocol === "https:" ? httpsRequest : httpRequest)(url, httpsOptions(options));
218
+ const proxyRequest = proxy.protocol === "https:" ? httpsRequest : httpRequest;
219
+ const proxyPort = Number(proxy.port || (proxy.protocol === "https:" ? 443 : 80));
220
+ if (url.protocol === "http:") {
221
+ return proxyRequest({
222
+ ...options, host: proxy.hostname, port: proxyPort, path: url.href,
223
+ headers: { ...options.headers, host: url.host, ...proxyAuth(proxy) },
224
+ });
225
+ }
226
+ const port = Number(url.port || 443);
227
+ const createConnection = (_opts, done) => {
228
+ const connect = proxyRequest({
229
+ host: proxy.hostname, port: proxyPort, method: "CONNECT", path: `${url.hostname}:${port}`,
230
+ headers: { host: `${url.hostname}:${port}`, ...proxyAuth(proxy) },
231
+ });
232
+ connect.on("error", (e) => done(e));
233
+ connect.on("connect", (res, socket) => {
234
+ if (res.statusCode !== 200) {
235
+ socket.destroy();
236
+ done(new Error(`the proxy ${proxy.host} refused CONNECT ${url.host} (HTTP ${res.statusCode})`));
237
+ return;
238
+ }
239
+ done(null, tlsConnect({ socket, servername: url.hostname, ALPNProtocols: ["http/1.1"], checkServerIdentity: guardCertChain }));
240
+ });
241
+ connect.end();
242
+ return undefined;
243
+ };
244
+ const { agent: _agent, ...direct } = options;
245
+ return httpsRequest(url, {
246
+ ...direct,
247
+ createConnection: createConnection,
248
+ });
249
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Interactive terminals: `GET /v1/sandboxes/:id/pty` over a WebSocket (RFC 6455).
3
+ *
4
+ * The protocol:
5
+ *
6
+ * client → server binary = keystrokes; text = `{"resize":{cols,rows}}` | `{"signal":N}` | `{"eof":true}`
7
+ * server → client binary = terminal output; text = `{"event":"open",…}` first and
8
+ * `{"event":"exit"|"error"|"closed",…}` last, then a Close frame
9
+ *
10
+ * Zero dependencies, so this is a small client over `node:http` rather than the global
11
+ * `WebSocket`: that one cannot send an `Authorization` header, and a key in the query string is
12
+ * a key in every access log between here and the sandbox.
13
+ */
14
+ /** Largest terminal input frame sent; the server's cap is 1 MiB per client frame. */
15
+ export declare const PTY_INPUT_CHUNK: number;
16
+ /** How much of what was typed a session keeps, to send again to a terminal picked up again. */
17
+ export declare const PTY_INPUT_KEEP: number;
18
+ /** The header a terminal is picked up again with (its resume token). */
19
+ export declare const PTY_RESUME_HEADER = "promigence-resume";
20
+ export interface PtySize {
21
+ cols: number;
22
+ rows: number;
23
+ }
24
+ /** How a terminal ended. `exitCode` is `null` when the shell died of a signal. */
25
+ export interface PtyExit {
26
+ exitCode: number | null;
27
+ signal: number | null;
28
+ wallMs?: number;
29
+ /** Set when the session ended without an exit record (`error`, or the socket just closed). */
30
+ error?: {
31
+ code: string;
32
+ message: string;
33
+ };
34
+ }
35
+ /** The header the terminal's command travels in, base64. Never a query parameter. */
36
+ export declare const PTY_COMMAND_HEADER = "promigence-pty-command";
37
+ /** The header the terminal's secret **names** travel in, base64 JSON. */
38
+ export declare const PTY_SECRETS_HEADER = "promigence-pty-secrets";
39
+ export interface PtyConnectOpts {
40
+ /** `http(s)://host[:port]/v1/sandboxes/<id>/pty?cols=&rows=` — dimensions only. */
41
+ url: string;
42
+ apiKey: string;
43
+ userAgent: string;
44
+ /**
45
+ * The command to run, sent as a header rather than in the URL.
46
+ *
47
+ * It used to be `?cmd=`, with `envs` composed into it as `export K=v;` — so a terminal opened
48
+ * with an API key in its environment wrote that key into the query string of every request,
49
+ * and therefore into every access log along the path. Names and values both stay out of the
50
+ * URL now.
51
+ */
52
+ command?: string;
53
+ /** Stored secret names (or `{name, as}` bindings), resolved server-side into the terminal's
54
+ * environment. JSON, base64, in a header. */
55
+ secrets?: unknown[];
56
+ /** The `promigence-caller` label, when one is set (`setCaller`). */
57
+ caller?: string;
58
+ onData?: (data: Uint8Array) => void;
59
+ onExit?: (exit: PtyExit) => void;
60
+ /**
61
+ * Reconnect in a new shell when the service is updated (a WebSocket `Close` 1012) and the
62
+ * terminal cannot be picked up again ([`resume`]). The session goes on over a new connection,
63
+ * with its callbacks, its size and what was typed meanwhile, in a NEW shell: what ran in the old
64
+ * one has ended. Tried for up to 30 s ([`PTY_RECONNECT_FOR_MS`]); past that the session ends with
65
+ * `error.code` `"service_restart"`.
66
+ *
67
+ * Default: on for a shell, off when `command` is set (reconnecting starts the command again,
68
+ * which may not be safe to run twice); `true` or `false` decides either way.
69
+ */
70
+ reconnect?: boolean;
71
+ /**
72
+ * Pick the same terminal up again when its connection drops or the service restarts (default
73
+ * on): the terminal keeps running for a short while, and the session picks up where it left off
74
+ * over a new connection, with what was typed meanwhile delivered once — the same shell, or the
75
+ * same command, still running. Where it cannot be picked up (it ended meanwhile, or too much time
76
+ * passed), a restart falls back to [`reconnect`]; a dropped connection ends the session, as
77
+ * before.
78
+ */
79
+ resume?: boolean;
80
+ /**
81
+ * Called after each reconnect: `resumed` is `true` when it is the same terminal picked up
82
+ * again, `false` when it is a new shell (what ran in the old one has ended).
83
+ */
84
+ onReconnected?: (how: {
85
+ resumed: boolean;
86
+ }) => void;
87
+ /** Handshake bound (default 30 s). The session itself has none. */
88
+ timeoutMs?: number;
89
+ /** Maps a refused upgrade (`status`, body text, its `Retry-After`) onto the SDK's error classes. */
90
+ refuse: (status: number, body: string, retryAfter?: string) => Error;
91
+ }
92
+ /** The accept value a server must echo for `key` (RFC 6455 §4.2.2). */
93
+ export declare function wsAccept(key: string): string;
94
+ /** One client → server frame: FIN, the opcode, a 4-byte mask (mandatory from a client). */
95
+ export declare function encodeFrame(opcode: number, payload: Uint8Array): Buffer;
96
+ /**
97
+ * Incremental frame decoder. Feed it bytes as they arrive; it returns whole frames. Continuation
98
+ * frames are reassembled, so a server that fragments is read correctly.
99
+ */
100
+ export declare class FrameReader {
101
+ private buf;
102
+ private partial;
103
+ push(chunk: Uint8Array): Array<{
104
+ opcode: number;
105
+ payload: Buffer;
106
+ }>;
107
+ }
108
+ /**
109
+ * A live terminal. Resolved by [`connectPty`] once the server's `open` event has arrived, so a
110
+ * keystroke written immediately is never written into a pty that does not exist yet.
111
+ */
112
+ export declare class PtySession {
113
+ #private;
114
+ private socket;
115
+ /**
116
+ * The id of the terminal's process inside the sandbox (`req_id`); what `pty.kill(pid)`
117
+ * addresses. It names this session: it stays the same after a reconnect.
118
+ */
119
+ readonly pid: number;
120
+ cols: number;
121
+ rows: number;
122
+ private closed;
123
+ private readonly done;
124
+ /** Frames written while the session reconnects, sent once it has (at most 1 MiB). */
125
+ private pending;
126
+ /** Keystrokes written to a connection, in all, and the last of them, from `inputBase` on: what a
127
+ * terminal picked up again did not take is sent again. */
128
+ private inputSent;
129
+ private inputBase;
130
+ private inputLog;
131
+ /** `true` once the terminal has ended (its exit arrived, or the socket closed). */
132
+ get ended(): boolean;
133
+ private flush;
134
+ /** Write a frame to the connection now, counting keystrokes. */
135
+ private writeNow;
136
+ private send;
137
+ /** Keystrokes / a paste. A string is sent as UTF-8. */
138
+ write(data: string | Uint8Array): void;
139
+ resize(size: PtySize): void;
140
+ /** Deliver a signal to the terminal's process group (`9` = SIGKILL). */
141
+ signal(sig: number): void;
142
+ /** Close the terminal's stdin (`^D` without the line discipline). */
143
+ eof(): void;
144
+ /** Resolves with how the terminal ended. Never rejects. */
145
+ wait(): Promise<PtyExit>;
146
+ /**
147
+ * Hang up. The shell is sent `SIGHUP` when the socket goes away, which is what a
148
+ * terminal emulator closing its window does.
149
+ */
150
+ disconnect(): void;
151
+ }
152
+ /** The `Close` code a terminal is asked to reconnect with: 1012, "service restart" (RFC 6455's registry). */
153
+ export declare const PTY_RECONNECT_CODE = 1012;
154
+ /** How long a terminal tries to reconnect before it ends (`error.code` `"service_restart"`). */
155
+ export declare const PTY_RECONNECT_FOR_MS = 30000;
156
+ /** The first wait before a reconnect, doubled each try up to [`PTY_RECONNECT_MAX_WAIT_MS`]; each wait is jittered (50-100 %). */
157
+ export declare const PTY_RECONNECT_FIRST_WAIT_MS = 250;
158
+ export declare const PTY_RECONNECT_MAX_WAIT_MS = 4000;
159
+ /** How a session that could not reconnect within [`PTY_RECONNECT_FOR_MS`] ends. */
160
+ export declare const PTY_RESTART_EXIT: PtyExit;
161
+ /** How a session that is not to reconnect (`reconnect` off, or a command's) ends at a 1012. */
162
+ export declare const PTY_RESTART_CLOSED_EXIT: PtyExit;
163
+ /**
164
+ * Open a terminal. Rejects with `opts.refuse(...)` if the server does not switch protocols.
165
+ *
166
+ * When its connection drops, or the service asks it to reconnect (`Close` 1012), the session goes
167
+ * on over a new connection: the same terminal picked up again where the service still holds it
168
+ * ([`PtyConnectOpts.resume`]), else, at a restart, a new shell ([`PtyConnectOpts.reconnect`]).
169
+ * `wait()` resolves only when the session really ends.
170
+ */
171
+ export declare function connectPty(opts: PtyConnectOpts): Promise<PtySession>;