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
package/dist/io.js ADDED
@@ -0,0 +1,318 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { ERRORS_DOCS_URL, PromigenceError, configDir, } from "./sdk/index.js";
3
+ import { DOCS_URL, EXIT_PRECEDENCE, GUIDE_POINTER, SCHEMA, VERSION, } from "./surface.js";
4
+ import { usd } from "./money.js";
5
+ import { fieldForTerminal, jsonLine } from "./term.js";
6
+ const seenGuidePath = () => `${configDir()}/seen-guide`;
7
+ export const seenGuide = () => existsSync(seenGuidePath());
8
+ export function markGuideSeen() {
9
+ try {
10
+ mkdirSync(configDir(), { recursive: true });
11
+ writeFileSync(seenGuidePath(), `${new Date().toISOString()} promigence@${VERSION}\n`);
12
+ }
13
+ catch { }
14
+ }
15
+ let pipeGuardInstalled = false;
16
+ export function isGoneReader(code) {
17
+ return code === "EPIPE" || code === "ENOTCONN" || code === "ECONNRESET";
18
+ }
19
+ function guardPipe() {
20
+ if (pipeGuardInstalled)
21
+ return;
22
+ pipeGuardInstalled = true;
23
+ const handle = (exitOnEpipe) => (err) => {
24
+ if (isGoneReader(err.code)) {
25
+ if (exitOnEpipe)
26
+ process.exit(0);
27
+ return;
28
+ }
29
+ throw err;
30
+ };
31
+ process.stdout.on("error", handle(true));
32
+ process.stderr.on("error", handle(false));
33
+ }
34
+ export function writeBytes(stream, data) {
35
+ if (!data.length)
36
+ return Promise.resolve();
37
+ guardPipe();
38
+ return new Promise((resolve) => {
39
+ stream.write(data, () => resolve());
40
+ });
41
+ }
42
+ export function write(stream, text) {
43
+ if (!text)
44
+ return Promise.resolve();
45
+ guardPipe();
46
+ return new Promise((resolve) => {
47
+ stream.write(text, () => resolve());
48
+ });
49
+ }
50
+ function flush(stream) {
51
+ guardPipe();
52
+ return new Promise((resolve) => {
53
+ stream.write("", () => resolve());
54
+ });
55
+ }
56
+ let beforeExit;
57
+ export function setBeforeExit(fn) {
58
+ beforeExit = fn;
59
+ }
60
+ export async function exitWith(code) {
61
+ const hook = beforeExit;
62
+ beforeExit = undefined;
63
+ if (hook)
64
+ await hook().catch(() => undefined);
65
+ await flush(process.stdout);
66
+ await flush(process.stderr);
67
+ process.exit(code);
68
+ throw new Error("unreachable");
69
+ }
70
+ let accountNotice;
71
+ export function recordNotice(n) {
72
+ accountNotice ??= n;
73
+ }
74
+ export function noticeLine(n) {
75
+ return `promigence: notice (${n.code}): ${n.message ?? ""}${n.fix ? ` — ${n.fix}` : ""}`;
76
+ }
77
+ export const PLACEHOLDER = /<[a-z][a-z_ -]*>/i;
78
+ export async function emit(mode, env, textLines, exit, pointer, textTo = "payload") {
79
+ const showPointer = pointer && !seenGuide();
80
+ env.next = (env.next ?? []).filter((n) => !PLACEHOLDER.test(n.cmd));
81
+ if (!env.ok && env.error && env.error.exit === undefined) {
82
+ env.error.exit = typeof env.promigence_exit === "number" ? env.promigence_exit : exit;
83
+ }
84
+ if (mode === "json") {
85
+ if (showPointer)
86
+ env.hint = GUIDE_POINTER;
87
+ if (accountNotice)
88
+ env.notice = accountNotice;
89
+ await write(process.stdout, jsonLine(process.stdout, env));
90
+ }
91
+ else {
92
+ if (showPointer && !process.stdout.isTTY)
93
+ await write(process.stderr, GUIDE_POINTER + "\n");
94
+ if (accountNotice)
95
+ await write(process.stderr, fieldForTerminal(process.stderr, noticeLine(accountNotice)) + "\n");
96
+ const out = env.ok && textTo === "payload" ? process.stdout : process.stderr;
97
+ if (textLines.length)
98
+ await write(out, textLines.map((l) => fieldForTerminal(out, l)).join("\n") + "\n");
99
+ }
100
+ return exitWith(exit);
101
+ }
102
+ export function okEnvelope(command, fields, next) {
103
+ return { schema: SCHEMA, command, ok: true, ...fields, next };
104
+ }
105
+ export function noCommandFix(example, platform = process.platform) {
106
+ return platform === "win32"
107
+ ? `${example} PowerShell removes a bare --: write '--' in quotes, or run promigence.cmd.`
108
+ : example;
109
+ }
110
+ export function usageError(message, fix) {
111
+ return new PromigenceError({ code: "usage", message, fix, exitCode: 2, docs: USAGE_DOCS });
112
+ }
113
+ export const USAGE_DOCS = `${ERRORS_DOCS_URL}#usage`;
114
+ export function overMost(flag, given, most, mostText, page = false) {
115
+ process.stderr.write(page
116
+ ? `promigence: ${flag} ${given} is over the most one page holds (${mostText}); asking for ${mostText} (pass the answer's next_cursor with --cursor for the rest)\n`
117
+ : `promigence: ${flag} ${given} is over the most (${mostText}); asking for ${mostText}\n`);
118
+ return most;
119
+ }
120
+ const LOCAL_PATH_ERRORS = {
121
+ ENOENT: "it does not exist",
122
+ ENOTDIR: "a part of the path is not a directory",
123
+ EISDIR: "it is a directory",
124
+ EACCES: "permission denied",
125
+ EPERM: "operation not permitted",
126
+ EEXIST: "it already exists",
127
+ EROFS: "the file system is read-only",
128
+ ENOSPC: "the disk is full",
129
+ EDQUOT: "the disk quota is used up",
130
+ ENAMETOOLONG: "the name is too long",
131
+ ELOOP: "it is a symbolic link loop, or a link where a file was expected",
132
+ };
133
+ export function toPromigenceError(err) {
134
+ if (err instanceof PromigenceError)
135
+ return err;
136
+ const e = err;
137
+ if (typeof e?.code === "string" && typeof e.path === "string" && LOCAL_PATH_ERRORS[e.code] !== undefined) {
138
+ return new PromigenceError({
139
+ code: "usage",
140
+ message: `${e.path}: ${LOCAL_PATH_ERRORS[e.code]} (${e.code}${e.syscall ? ` on ${e.syscall}` : ""})`,
141
+ fix: "Check the local path: that its directory exists, that you can write there, and that it names a file where a file is expected.",
142
+ exitCode: 2,
143
+ });
144
+ }
145
+ return new PromigenceError({
146
+ code: "internal",
147
+ message: `internal error: ${e?.message ?? String(err)}`,
148
+ fix: "Not your fault. Re-run; if it repeats, report it with the command line and promigence --version.",
149
+ exitCode: 1,
150
+ });
151
+ }
152
+ export function errorEnvelope(command, err, next) {
153
+ return {
154
+ schema: SCHEMA,
155
+ command,
156
+ ok: false,
157
+ error: {
158
+ code: err.code, message: err.message, fix: err.fix, docs: err.docs || DOCS_URL, guide: err.guide,
159
+ ...(err.requestId === undefined ? {} : { request_id: err.requestId }),
160
+ ...(err.category === undefined ? {} : { category: err.category }),
161
+ ...(err.retryable === undefined ? {} : { retryable: err.retryable }),
162
+ },
163
+ next,
164
+ };
165
+ }
166
+ export function errorTextLines(command, err, exit, next) {
167
+ const lines = [
168
+ exit === 125 && err.cliExit !== 125
169
+ ? `promigence ${command}: ${err.message} (error ${err.code}, exit 125: Promigence's own failure, not the command's; without passthrough it is exit ${err.cliExit})`
170
+ : `promigence ${command}: ${err.message} (error ${err.code}, exit ${exit})`,
171
+ ` fix: ${err.fix}`,
172
+ ];
173
+ if (next.length)
174
+ lines.push(` next: ${next.map((n) => n.cmd).join(" · ")}`);
175
+ if (err.requestId !== undefined)
176
+ lines.push(` request: ${err.requestId}`);
177
+ return lines;
178
+ }
179
+ export function pickExit(codes) {
180
+ let best = 0;
181
+ let bestRank = EXIT_PRECEDENCE.indexOf(0);
182
+ for (const c of codes) {
183
+ const rank = EXIT_PRECEDENCE.indexOf(c);
184
+ if (rank === -1)
185
+ return c;
186
+ if (rank < bestRank) {
187
+ best = c;
188
+ bestRank = rank;
189
+ }
190
+ }
191
+ return best;
192
+ }
193
+ const BARE_SECONDS = /^\d+(?:\.\d+)?$/;
194
+ const DURATION = /^(?:\d+(?:\.\d+)?(?:ms|s|m|h))+$/;
195
+ const DURATION_PART = /(\d+(?:\.\d+)?)(ms|s|m|h)/g;
196
+ export function parseDuration(value, flag) {
197
+ const v = value.trim();
198
+ if (BARE_SECONDS.test(v))
199
+ return Math.round(Number(v) * 1000);
200
+ if (!DURATION.test(v)) {
201
+ throw usageError(`${flag}: '${value}' is not a duration`, `Use a number with a unit: ${flag} 15m (also ms, s, h, or parts like 2m10s; a bare number is seconds).`);
202
+ }
203
+ let total = 0;
204
+ for (const [, n, unit] of v.matchAll(DURATION_PART)) {
205
+ total += Number(n) * (unit === "ms" ? 1 : unit === "s" ? 1000 : unit === "m" ? 60_000 : 3_600_000);
206
+ }
207
+ return Math.round(total);
208
+ }
209
+ export function parseCommandTimeout(value, flag) {
210
+ const ms = parseDuration(value, flag);
211
+ if (ms <= 0) {
212
+ throw usageError(`${flag}: a command timeout must be more than 0`, `Omit ${flag} for the default, or pass a bound: ${flag} 30m.`);
213
+ }
214
+ return ms;
215
+ }
216
+ export function parseCount(value, flag) {
217
+ const n = Number(value);
218
+ if (!Number.isInteger(n) || n < 1) {
219
+ throw usageError(`${flag}: '${value}' is not a positive integer`, `Pass ${flag} N with N >= 1.`);
220
+ }
221
+ return n;
222
+ }
223
+ export function parseUsd(value, flag) {
224
+ const n = Number(value);
225
+ if (!Number.isFinite(n) || n < 0) {
226
+ throw usageError(`${flag}: '${value}' is not a dollar amount`, `Pass ${flag} USD, e.g. ${flag} 1 (dollars, not cents).`);
227
+ }
228
+ return n;
229
+ }
230
+ export const MAX_OUTPUT_CEILING = 32 * 1024 * 1024;
231
+ export function parseMaxOutput(value, flag = "--max-output") {
232
+ const n = parseBytes(value, flag);
233
+ return n > MAX_OUTPUT_CEILING ? overMost(flag, value, MAX_OUTPUT_CEILING, "32m") : n;
234
+ }
235
+ export function parseBytes(value, flag) {
236
+ const m = /^(\d+)([km])?$/i.exec(value.trim());
237
+ if (!m)
238
+ throw usageError(`${flag}: '${value}' is not a byte count`, `Pass ${flag} 64k (k = KiB, m = MiB, or plain bytes).`);
239
+ const n = Number(m[1]);
240
+ const unit = (m[2] ?? "").toLowerCase();
241
+ return unit === "k" ? n * 1024 : unit === "m" ? n * 1024 * 1024 : n;
242
+ }
243
+ export const ms = (n) => (n === undefined ? "—" : `${Math.round(n)}ms`);
244
+ export function forkLine(fork) {
245
+ if (!fork)
246
+ return "fork: (no timings yet)";
247
+ const p = (name, v) => v === undefined ? `${name} —` : `${name} p50 ${ms(v.p50)} p95 ${ms(v.p95)}${v.p99 === undefined ? "" : ` p99 ${ms(v.p99)}`}`;
248
+ return [
249
+ `fork n=${fork.n} (on our side)`,
250
+ p("queued", fork.queued_ms),
251
+ p("ready", fork.ready_ms),
252
+ p("e2e", fork.e2e_ms),
253
+ ].join(" · ");
254
+ }
255
+ export function totalsLine(t) {
256
+ if (!t)
257
+ return "totals: (none)";
258
+ const parts = Object.entries(t).filter(([, v]) => typeof v === "number" && v > 0).map(([k, v]) => `${k} ${v}`);
259
+ return `totals: ${parts.length ? parts.join(" · ") : "none"}`;
260
+ }
261
+ export function forkSummary(fork) {
262
+ if (!fork)
263
+ return {};
264
+ const out = {
265
+ n: fork.n,
266
+ warm_retries: fork.warm_retries,
267
+ first_attempt_success_pct: fork.first_attempt_success_pct,
268
+ final_success_pct: fork.final_success_pct,
269
+ };
270
+ for (const k of ["queued_ms", "ready_ms", "e2e_ms", "verify_each_ms"]) {
271
+ const v = fork[k];
272
+ if (v !== undefined)
273
+ out[k] = v;
274
+ }
275
+ return out;
276
+ }
277
+ export function reportSummaryLines(report) {
278
+ const lines = [
279
+ `run ${report.run_id}: ${report.state}` + (report.snapshot_id ? ` · snapshot ${report.snapshot_id}` : ""),
280
+ ` ${forkLine(report.fork)}`,
281
+ ` ${totalsLine(report.totals)}`,
282
+ ];
283
+ const g = gradeLine(report.grade);
284
+ if (g)
285
+ lines.push(` ${g}`);
286
+ if (report.cost) {
287
+ const secs = report.cost.billable_seconds !== undefined ? ` · ${report.cost.billable_seconds} billable s` : "";
288
+ lines.push(` cost: quoted ${usd(report.cost.quoted)} · charged ${usd(report.cost.charged)} · unbilled ${usd(report.cost.unbilled)}${secs}`);
289
+ }
290
+ for (const s of report.sandboxes ?? []) {
291
+ const graded = s.graded === true && (s.passed !== undefined || s.holdout_passed !== undefined);
292
+ if (s.outcome === "completed" && !s.failure && !graded)
293
+ continue;
294
+ const f = s.failure ? ` (${s.failure.category}/${s.failure.code})` : "";
295
+ const billed = s.billable_seconds !== undefined ? ` · ${s.billable_seconds}s ${usd(s.cost ?? 0)}` : "";
296
+ lines.push(` ${s.sandbox_id}: ${s.outcome}${f}${graded ? ` · ${sandboxGrade(s)}` : ""}${billed}`);
297
+ }
298
+ return lines;
299
+ }
300
+ export function sandboxGrade(s) {
301
+ const verdict = (p, sc) => p === undefined ? "-" : `${p ? "pass" : "fail"}${sc === undefined ? "" : ` ${Number(sc.toFixed(4))}`}`;
302
+ const held = s.holdout_passed !== undefined || s.holdout_score !== undefined
303
+ ? ` · held-out ${verdict(s.holdout_passed, s.holdout_score)}`
304
+ : "";
305
+ return `tests ${verdict(s.passed, s.score)}${held}`;
306
+ }
307
+ export function gradeLine(g) {
308
+ if (!g)
309
+ return undefined;
310
+ const parts = [`graded ${g.graded}`, `tests ${g.pass_pct.toFixed(1)}%`];
311
+ if (g.holdout_pass_pct !== undefined)
312
+ parts.push(`held-out ${g.holdout_pass_pct.toFixed(1)}%`);
313
+ if (g.gap_pct !== undefined)
314
+ parts.push(`gap ${g.gap_pct.toFixed(1)} points`);
315
+ if (g.grader_failed)
316
+ parts.push(`grader_failed ${g.grader_failed}`);
317
+ return `grade: ${parts.join(" · ")}`;
318
+ }