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,82 @@
1
+ /**
2
+ * `CommandHandle` — the handle `commands.run(cmd, { background: true })` returns.
3
+ *
4
+ * Output is read the way the API serves it: by byte range, polled. There is no second streaming
5
+ * transport for background execs, and a poll at 100–500 ms is below the resolution anyone reads a
6
+ * dev server's log at. `wait()` parks on the API's `wait_ms` long-poll between reads, so a
7
+ * process that ends is noticed within one round trip, not one poll interval.
8
+ *
9
+ * Stated once: `pid` is the API's `exec_id` (a string), not a process number —
10
+ * it is what `commands.kill(pid)` and `commands.connect(pid)` take.
11
+ */
12
+ import { type CommandResult } from "./core.js";
13
+ import { inspect, type InspectOptions } from "node:util";
14
+ import type { BackgroundExecRecord, PromigenceClient } from "./client.js";
15
+ export interface CommandHandleOpts {
16
+ onStdout?: (data: string) => void;
17
+ onStderr?: (data: string) => void;
18
+ /** Poll interval while only callbacks are attached (default 250 ms). */
19
+ pollMs?: number;
20
+ /**
21
+ * The bound the command was started with, in ms: `wait()` then throws `CommandTimeoutError`
22
+ * for a command killed there rather than a bare `CommandExitError(137)`.
23
+ */
24
+ timeoutMs?: number;
25
+ }
26
+ export declare class CommandHandle {
27
+ #private;
28
+ /** The `exec_id`. */
29
+ readonly pid: string;
30
+ readonly sandboxId: string;
31
+ /** Everything read so far, decoded as UTF-8. */
32
+ stdout: string;
33
+ stderr: string;
34
+ private readonly opts;
35
+ private readonly offset;
36
+ private readonly decoder;
37
+ private record;
38
+ private pumping;
39
+ private stopped;
40
+ private draining;
41
+ constructor(client: PromigenceClient, record: BackgroundExecRecord, opts?: CommandHandleOpts);
42
+ /** The last status the API reported. */
43
+ get state(): BackgroundExecRecord["state"];
44
+ get exitCode(): number | undefined;
45
+ get error(): string | undefined;
46
+ /** Started with `stdin: true`, so `sendStdin` / `closeStdin` reach the process. */
47
+ get stdinOpen(): boolean;
48
+ /**
49
+ * Write to the process's standard input. Text is sent as UTF-8; bytes are sent as they are.
50
+ *
51
+ * Only for a command started with `{ stdin: true }` — a child's stdin cannot be opened after
52
+ * it has been spawned, and this throws (`no_stdin`) rather than dropping the bytes.
53
+ */
54
+ sendStdin(data: string | Uint8Array): Promise<number>;
55
+ /**
56
+ * Close stdin (EOF). A process reading to end-of-input — `sort`, `cat`, a REPL — does nothing
57
+ * until this arrives, so it is the other half of `sendStdin` and not an optional tidy-up.
58
+ */
59
+ closeStdin(): Promise<void>;
60
+ /** Read every byte that is buffered now, on both streams. Serialised: one drain at a time. */
61
+ private drain;
62
+ private pump;
63
+ /**
64
+ * Wait for the process to end and return its result. A non-zero exit throws
65
+ * `CommandExitError` (it carries `stdout`/`stderr`/`exitCode`); a command killed at the
66
+ * `timeoutMs` it was started with throws `CommandTimeoutError`, a `CommandExitError` that says so.
67
+ */
68
+ wait(): Promise<CommandResult>;
69
+ /** SIGKILL. `true` if the process was running and the signal was delivered. */
70
+ kill(): Promise<boolean>;
71
+ /** Stop polling for output. The process keeps running; `commands.connect(pid)` re-attaches. */
72
+ disconnect(): Promise<void>;
73
+ /** What `JSON.stringify` shows: ids and status. The client (and its key) is never part of it. */
74
+ toJSON(): {
75
+ pid: string;
76
+ sandboxId: string;
77
+ state: BackgroundExecRecord["state"];
78
+ exitCode: number | undefined;
79
+ };
80
+ /** What `console.log` / `util.inspect` show: the same as `toJSON`. */
81
+ [inspect.custom](_depth: number, opts: InspectOptions): string;
82
+ }
@@ -0,0 +1,135 @@
1
+ import { CommandExitError, EnvFailedError } from "./core.js";
2
+ import { inspect } from "node:util";
3
+ import { CommandTimeoutError, exitTimedOut } from "./command-errors.js";
4
+ const HANDLE_WAIT_MS = 30_000;
5
+ const HANDLE_POLL_MS = 250;
6
+ export class CommandHandle {
7
+ pid;
8
+ sandboxId;
9
+ stdout = "";
10
+ stderr = "";
11
+ #client;
12
+ opts;
13
+ offset = { stdout: 0, stderr: 0 };
14
+ decoder = { stdout: new TextDecoder(), stderr: new TextDecoder() };
15
+ record;
16
+ pumping = false;
17
+ stopped = false;
18
+ draining;
19
+ constructor(client, record, opts = {}) {
20
+ this.#client = client;
21
+ this.record = record;
22
+ this.pid = record.exec_id;
23
+ this.sandboxId = record.sandbox_id;
24
+ this.opts = opts;
25
+ if (opts.onStdout || opts.onStderr)
26
+ void this.pump();
27
+ }
28
+ get state() { return this.record.state; }
29
+ get exitCode() {
30
+ const e = this.record.exit;
31
+ if (!e)
32
+ return undefined;
33
+ return e.exit_code ?? (e.signal ? 128 + e.signal : -1);
34
+ }
35
+ get error() { return this.record.error?.msg; }
36
+ get stdinOpen() { return Boolean(this.record.stdin_open); }
37
+ async sendStdin(data) {
38
+ const r = await this.#client.sandboxes.execs.stdin(this.sandboxId, this.pid, { data });
39
+ return r.written;
40
+ }
41
+ async closeStdin() {
42
+ await this.#client.sandboxes.execs.stdin(this.sandboxId, this.pid, { eof: true });
43
+ }
44
+ drain() {
45
+ const run = async () => {
46
+ for (const s of ["stdout", "stderr"]) {
47
+ for (;;) {
48
+ const r = await this.#client.sandboxes.execs.read(this.sandboxId, this.pid, s, { offset: this.offset[s] });
49
+ this.record = r.record;
50
+ if (r.data.length === 0)
51
+ break;
52
+ this.offset[s] += r.data.length;
53
+ const text = this.decoder[s].decode(r.data, { stream: true });
54
+ this[s] += text;
55
+ if (text)
56
+ (s === "stdout" ? this.opts.onStdout : this.opts.onStderr)?.(text);
57
+ if (r.eof)
58
+ break;
59
+ }
60
+ }
61
+ };
62
+ const next = (this.draining ?? Promise.resolve()).then(run, run);
63
+ this.draining = next.catch(() => { });
64
+ return next;
65
+ }
66
+ async pump() {
67
+ if (this.pumping)
68
+ return;
69
+ this.pumping = true;
70
+ try {
71
+ while (!this.stopped) {
72
+ await this.drain();
73
+ if (this.record.state !== "running") {
74
+ await this.drain();
75
+ break;
76
+ }
77
+ await new Promise((r) => { setTimeout(r, this.opts.pollMs ?? 250); });
78
+ }
79
+ }
80
+ catch {
81
+ }
82
+ finally {
83
+ this.pumping = false;
84
+ }
85
+ }
86
+ async wait() {
87
+ for (;;) {
88
+ await this.drain();
89
+ if (this.record.state !== "running")
90
+ break;
91
+ this.record = await this.#client.sandboxes.execs.get(this.sandboxId, this.pid, { waitMs: HANDLE_WAIT_MS });
92
+ if (this.record.state === "running" && !((this.record.waited_ms ?? 0) >= HANDLE_WAIT_MS)) {
93
+ await new Promise((r) => { setTimeout(r, HANDLE_POLL_MS); });
94
+ }
95
+ }
96
+ await this.drain();
97
+ for (const s of ["stdout", "stderr"]) {
98
+ const tail = this.decoder[s].decode();
99
+ if (tail) {
100
+ this[s] += tail;
101
+ (s === "stdout" ? this.opts.onStdout : this.opts.onStderr)?.(tail);
102
+ }
103
+ }
104
+ if (this.record.state === "failed") {
105
+ const e = this.record.error;
106
+ throw new EnvFailedError(e?.code ?? "sandbox_unresponsive", `background exec ${this.pid} failed: ${e?.msg ?? "no exit record"}`, "Not your command's failure. Check the sandbox is still ready (`promigence run report <run_id>`) and start it again.");
107
+ }
108
+ const result = {
109
+ exitCode: this.exitCode ?? -1,
110
+ stdout: this.stdout,
111
+ stderr: this.stderr,
112
+ truncated: Boolean(this.record.truncated),
113
+ execId: this.pid,
114
+ };
115
+ if (result.exitCode !== 0) {
116
+ if (exitTimedOut(this.record.exit, this.opts.timeoutMs))
117
+ throw new CommandTimeoutError(result, this.opts.timeoutMs);
118
+ throw new CommandExitError(result);
119
+ }
120
+ return result;
121
+ }
122
+ async kill() {
123
+ const r = await this.#client.sandboxes.execs.signal(this.sandboxId, this.pid, "SIGKILL");
124
+ return r.delivered;
125
+ }
126
+ async disconnect() {
127
+ this.stopped = true;
128
+ }
129
+ toJSON() {
130
+ return { pid: this.pid, sandboxId: this.sandboxId, state: this.state, exitCode: this.exitCode };
131
+ }
132
+ [inspect.custom](_depth, opts) {
133
+ return `CommandHandle ${inspect(this.toJSON(), opts)}`;
134
+ }
135
+ }
@@ -0,0 +1,7 @@
1
+ const PLAIN = /^[A-Za-z0-9_./:@,][A-Za-z0-9_./:@,=-]*$/;
2
+ export function hintArg(value) {
3
+ const s = String(value);
4
+ if (PLAIN.test(s))
5
+ return s;
6
+ return `'${s.replace(/'/g, `'\\''`)}'`;
7
+ }