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/errfix.js ADDED
@@ -0,0 +1,262 @@
1
+ import { PREVIEWS_UNAVAILABLE, previewsFix } from "./sdk/index.js";
2
+ import { findCommand } from "./surface.js";
3
+ import { duration } from "./report.js";
4
+ import { sh } from "./term.js";
5
+ const SUPPORT = "support@promigence.ai";
6
+ const SDK_CALL = /^(?:secrets|snapshots|sandboxes|runs|execs|files|billing|keys|ports|images|orgs|projects|captures|referrals|credits)(?:\.[a-zA-Z]+)+:?\s/;
7
+ function reworded(e, fix, message = e.message) {
8
+ if (fix === e.fix && message === e.message)
9
+ return e;
10
+ const out = Object.create(Object.getPrototypeOf(e));
11
+ Object.assign(out, e);
12
+ out.fix = fix;
13
+ Object.defineProperty(out, "message", { value: message, writable: true, configurable: true, enumerable: false });
14
+ return out;
15
+ }
16
+ export function notFoundKind(message) {
17
+ const m = /^(.+?) `([^`]*)` not found$/.exec(message.trim());
18
+ return m ? { kind: m[1].toLowerCase(), id: m[2] } : undefined;
19
+ }
20
+ function notFoundFor(kind, ctx, apiFix) {
21
+ const sid = ctx.sandbox ?? "SID";
22
+ switch (kind) {
23
+ case "snapshot":
24
+ return undefined;
25
+ case "ref":
26
+ case "commit":
27
+ return {
28
+ fix: apiFix,
29
+ next: [{ cmd: "promigence repos", why: "the repositories you can build, each with its default branch" }],
30
+ };
31
+ case "exec":
32
+ return {
33
+ fix: `Check the exec id: \`${sh `promigence exec ps --sandbox ${sid}`}\` lists the background ones, \`${sh `promigence sandbox info ${sid}`}\` every one.`,
34
+ next: [{ cmd: sh `promigence exec ps --sandbox ${sid}`, why: "the background execs of this sandbox and their ids" }],
35
+ };
36
+ case "sandbox":
37
+ return {
38
+ fix: "Check the sandbox id: `promigence sandbox list` shows the live ones, `--state ended` the ones that finished.",
39
+ next: [{ cmd: "promigence sandbox list", why: "your sandboxes and their ids" }],
40
+ };
41
+ case "run":
42
+ return {
43
+ fix: "Check the run id: `promigence run list` shows your recent runs.",
44
+ next: [{ cmd: "promigence run list", why: "your recent runs and their ids" }],
45
+ };
46
+ case "capture": {
47
+ const run = ctx.args[0] ?? "RUN";
48
+ return {
49
+ fix: `This run has no preserved failure left (deleted or expired): \`${sh `promigence run captures ${run}`}\` shows what is kept.`,
50
+ next: [{ cmd: sh `promigence run captures ${run}`, why: "what of this run is still preserved" }],
51
+ };
52
+ }
53
+ case "build":
54
+ return {
55
+ fix: "Check the build id: `promigence snapshot builds` shows your recent builds.",
56
+ next: [{ cmd: "promigence snapshot builds", why: "your recent builds and their ids" }],
57
+ };
58
+ case "key":
59
+ return {
60
+ fix: "Check the key id: `promigence keys list` shows this organization's keys.",
61
+ next: [{ cmd: "promigence keys list", why: "the keys and their ids" }],
62
+ };
63
+ case "secret":
64
+ return {
65
+ fix: "Check the name: `promigence secrets list` shows the secrets stored for this project.",
66
+ next: [{ cmd: "promigence secrets list", why: "the secrets stored here" }],
67
+ };
68
+ case "file":
69
+ return {
70
+ fix: `Check the path: \`${sh `promigence files ls DIR --sandbox ${sid}`}\` lists a directory.`,
71
+ next: [{ cmd: sh `promigence files ls / --sandbox ${sid}`, why: "what is in the sandbox" }],
72
+ };
73
+ case "port":
74
+ return {
75
+ fix: `Check the port: \`${sh `promigence port list --sandbox ${sid}`}\` shows the published ones.`,
76
+ next: [{ cmd: sh `promigence port list --sandbox ${sid}`, why: "the published ports" }],
77
+ };
78
+ case "referral":
79
+ case "referral code":
80
+ return {
81
+ fix: "Check the code with whoever gave it to you; it is not one this service knows. Your own code is in `promigence referrals`.",
82
+ next: [{ cmd: "promigence referrals", why: "your own code and your referrals" }],
83
+ };
84
+ case "project":
85
+ return {
86
+ fix: "Check the project: `promigence project list` shows this organization's projects.",
87
+ next: [{ cmd: "promigence project list", why: "the projects and their ids" }],
88
+ };
89
+ case "org":
90
+ return {
91
+ fix: "Check the organization: `promigence org list --all` shows every one you belong to.",
92
+ next: [{ cmd: "promigence org list", why: "your organizations" }],
93
+ };
94
+ case "template":
95
+ return {
96
+ fix: "Check the name: `promigence templates` lists every template by name.",
97
+ next: [{ cmd: "promigence templates", why: "the templates and their names" }],
98
+ };
99
+ default:
100
+ return {
101
+ fix: "Check the id, and that it belongs to the organization and project of the key you are using (`promigence me`).",
102
+ next: [{ cmd: "promigence me", why: "which organization this key acts in" }],
103
+ };
104
+ }
105
+ }
106
+ const BILLING_CMD = /`promigence billing (?:card|portal)`/;
107
+ export function withoutBilling(text) {
108
+ return text
109
+ .replace(/Owners: update the card with `promigence billing portal`; the hold lifts once the invoice is paid\.(?: For a disputed payment, write to support@promigence\.ai\.)?/, `To lift it, email ${SUPPORT}.`)
110
+ .replace(/,? or move to a plan that allows it: `promigence billing (?:card|portal)`\.?/, `, or email ${SUPPORT} for a plan that allows it.`)
111
+ .replace(/or add a card to lift it: `promigence billing (?:card|portal)`/, `or email ${SUPPORT} to lift it`)
112
+ .replace(/adding a card raises it \(owners: `promigence billing (?:card|portal)`\)\.?/, `to raise it, email ${SUPPORT}.`)
113
+ .replace(/Add a card to keep going \(owners: `promigence billing (?:card|portal)`[^)]*\)\.?/, `Card payments are not open yet: for more credits, email ${SUPPORT}.`)
114
+ .replace(/\(?owners: `promigence billing (?:card|portal)`(?:; members ask an owner)?\)?/g, `email ${SUPPORT}`)
115
+ .replace(/`promigence billing (?:card|portal)`/g, SUPPORT);
116
+ }
117
+ export const CREDIT_UNCLAIMED_FIX = "Claim your free credit first: `promigence credits claim` (owners; members ask an owner). Or add a card: `promigence billing card`.";
118
+ const ANY_HELP = /See `promigence [a-z][a-z -]* --help`\.?$/;
119
+ const API_WORDS = [
120
+ [/`timeout_ms`\s+(\d+)/g, "--timeout", (_m, ms) => `\`--timeout ${duration(Number(ms))}\``],
121
+ [/`timeout_ms`/g, "--timeout", "`--timeout`"],
122
+ [/`recursive(?:=true|: true)?`/g, "--recursive", "`--recursive`"],
123
+ [/\bpass recursive\b/g, "--recursive", "pass `--recursive`"],
124
+ [/`registry_secret`/g, "--registry-secret", "`--registry-secret`"],
125
+ [/`force(?:=true|: true)?`/g, "--force", "`--force`"],
126
+ [/`move_alias(?:=true|: true)?`/g, "--move-alias", "`--move-alias`"],
127
+ [/`state` is a comma-separated list/g, "--state", "`--state` is a comma-separated list"],
128
+ [/`network\.allow`/g, "--allow", "`--allow`"],
129
+ ];
130
+ export function inCliWords(text, command) {
131
+ const c = findCommand(command.split(" "));
132
+ if (!c)
133
+ return text;
134
+ let out = text;
135
+ for (const [re, flag, to] of API_WORDS) {
136
+ if (!c.flags.some((f) => f.name === flag))
137
+ continue;
138
+ out = out.replace(re, (...m) => {
139
+ const match = m[0];
140
+ const at = m[m.length - 2];
141
+ const whole = m[m.length - 1];
142
+ const clause = whole.slice(at + match.length).split(/[,;]|\.(?:\s|$)/)[0] ?? "";
143
+ if (/\bin the API\b/.test(clause))
144
+ return match;
145
+ return typeof to === "string" ? to : to(...m);
146
+ });
147
+ }
148
+ return out;
149
+ }
150
+ const SNAPSHOT_READS = new Set(["snapshot export", "snapshot inspect", "snapshot verify"]);
151
+ export async function refineError(e, ctx) {
152
+ let err = e;
153
+ let next;
154
+ if (/\{(sandbox_id|run_id)\}/.test(`${err.message} ${err.fix ?? ""}`)) {
155
+ const sid = ctx.sandbox ?? (ctx.command.startsWith("sandbox ") ? ctx.args[0] : undefined);
156
+ const fill = (t) => {
157
+ let out = t;
158
+ if (sid !== undefined)
159
+ out = out.replaceAll("{sandbox_id}", sid);
160
+ out = out.replaceAll("{sandbox_id}", "SID").replaceAll("{run_id}", "RUN_ID");
161
+ return out;
162
+ };
163
+ const fix = fill(err.fix ?? "");
164
+ const where = /RUN_ID/.test(fix) ? ` (RUN_ID: ${sid !== undefined ? sh `promigence sandbox info ${sid}` : "promigence sandbox info SID"} prints it)` : "";
165
+ err = reworded(err, fix ? `${fix}${where}` : fix, fill(err.message));
166
+ }
167
+ if (e.code === "sandbox_unresponsive") {
168
+ const sid = ctx.sandbox ?? (ctx.command.startsWith("sandbox ") ? ctx.args[0] : undefined);
169
+ next = [
170
+ ...(sid !== undefined
171
+ ? [{ cmd: sh `promigence sandbox kill ${sid}`, why: "end it: a sandbox that stopped answering does not come back by itself" }]
172
+ : []),
173
+ { cmd: "promigence fork --count 1 --cap 1", why: "a new sandbox" },
174
+ ];
175
+ }
176
+ if ((e.code === "usage" || e.code === "invalid_argument") && SDK_CALL.test(err.message)) {
177
+ err = reworded(err, err.fix ?? "", err.message.replace(SDK_CALL, (m) => (m.trim().endsWith(":") ? "" : `${ctx.command} `)));
178
+ }
179
+ if (e.code === "usage" || e.code === "invalid_argument") {
180
+ let fix = inCliWords(err.fix ?? "", ctx.command);
181
+ if (ANY_HELP.test(fix)) {
182
+ fix = fix.replace(ANY_HELP, `See \`promigence ${ctx.command} --help\`.`);
183
+ }
184
+ err = reworded(err, fix, inCliWords(err.message, ctx.command));
185
+ if (ctx.command === "snapshot delete" && /still has \d+ sandbox/.test(e.message)) {
186
+ fix = "End those sandboxes first (`promigence sandbox list` shows them; `promigence run kill RUN` ends a whole run), then delete it again.";
187
+ next = [{ cmd: "promigence sandbox list", why: "the sandboxes still running from it" }];
188
+ }
189
+ err = reworded(err, fix);
190
+ }
191
+ if (err.message === PREVIEWS_UNAVAILABLE) {
192
+ const sid = ctx.sandbox ?? "SID";
193
+ const port = /^\d+$/.test(ctx.args[0] ?? "") ? ctx.args[0] : "8000";
194
+ err = reworded(err, previewsFix(sid, port));
195
+ next = [{ cmd: sh `promigence sandbox ssh ${sid} -- -N -L ${`${port}:localhost:${port}`}`, why: "reach the port from this machine over SSH, until Ctrl-C" }];
196
+ }
197
+ if (e.code === "auth" && ctx.command === "sandbox ssh" && /^(this ssh access|sandbox \S+ has ended)/.test(e.message)) {
198
+ const sid = ctx.args[0] ?? "SID";
199
+ next = /has ended$/.test(e.message)
200
+ ? [{ cmd: "promigence sandbox list", why: "the sandboxes still running" }]
201
+ : [{ cmd: sh `promigence sandbox ssh ${sid}`, why: "new ssh access to the sandbox" }];
202
+ }
203
+ if (e.code === "not_found") {
204
+ const nf = notFoundKind(e.message);
205
+ const fitted = nf ? notFoundFor(nf.kind, ctx, err.fix ?? "") : undefined;
206
+ if (fitted) {
207
+ err = reworded(err, fitted.fix);
208
+ next = fitted.next;
209
+ }
210
+ }
211
+ if (e.code === "cap_exceeded" && ctx.command === "sandbox extend") {
212
+ const sid = ctx.args[0] ?? "SID";
213
+ err = reworded(err, "A sandbox can be extended only within what its run was quoted at launch (and at most its --cap), " +
214
+ "and that is used up. Start a new sandbox with the longer --timeout and a --cap that covers it.");
215
+ next = [
216
+ { cmd: sh `promigence sandbox info ${sid}`, why: "its timeout and what it has used" },
217
+ { cmd: "promigence fork --count 1 --timeout DUR --cap USD", why: "a sandbox with the longer timeout from the start" },
218
+ ];
219
+ }
220
+ if (e.code === "cap_exceeded" && ctx.command === "run open") {
221
+ const rid = ctx.args[0] ?? "RUN";
222
+ err = reworded(err, "The reopened sandbox is paid from what is left of its run's cap, and that does not cover it. " +
223
+ "Give the reopened sandbox its own --cap (and a --timeout).");
224
+ next = [
225
+ { cmd: sh `promigence run open ${rid} --cap 1 --timeout 10m`, why: "reopen it with its own cap" },
226
+ { cmd: sh `promigence run captures ${rid}`, why: "what of this run is preserved, and until when" },
227
+ ];
228
+ }
229
+ if (e.code === "unreachable" && /the sandbox host/.test(e.message)) {
230
+ const sid = ctx.sandbox ?? (ctx.command.startsWith("sandbox ") ? ctx.args[0] : undefined);
231
+ const snap = SNAPSHOT_READS.has(ctx.command) ? ctx.args[0] : undefined;
232
+ if (snap !== undefined) {
233
+ err = reworded(err, `The API is up but could not read this snapshot just now. Retry in a moment; if it keeps ` +
234
+ `happening, email ${SUPPORT} with the snapshot id.`);
235
+ next = [{ cmd: sh `promigence snapshot inspect ${snap}`, why: "the snapshot's state" }];
236
+ }
237
+ else if (sid !== undefined) {
238
+ err = reworded(err, `The API is up but could not reach this sandbox. Retry once; if it still does not answer, the sandbox has stopped responding ` +
239
+ `(\`sandbox info\` can still say ready): end it with \`${sh `promigence sandbox kill ${sid}`}\` and start a new one. ` +
240
+ `If it keeps happening, email ${SUPPORT} with the sandbox id.`);
241
+ next = [
242
+ { cmd: sh `promigence sandbox kill ${sid}`, why: "end it: a sandbox that stopped answering does not come back by itself" },
243
+ { cmd: "promigence fork --count 1 --cap 1", why: "a new sandbox" },
244
+ ];
245
+ }
246
+ else {
247
+ err = reworded(err, `The API is up but could not reach what this needed. Retry in a moment; if it keeps ` +
248
+ `happening, email ${SUPPORT} with the sandbox, run or snapshot id.`);
249
+ }
250
+ }
251
+ if (e.code === "credit_unclaimed") {
252
+ err = reworded(err, CREDIT_UNCLAIMED_FIX);
253
+ next = [
254
+ { cmd: "promigence credits claim", why: "open the claim page and accept the terms" },
255
+ { cmd: "promigence credits", why: "the free-credit offer for this account" },
256
+ ];
257
+ }
258
+ if ((BILLING_CMD.test(err.fix ?? "") || BILLING_CMD.test(err.message)) && await ctx.billingOff()) {
259
+ err = reworded(err, withoutBilling(err.fix ?? ""), withoutBilling(err.message));
260
+ }
261
+ return next ? { err, next } : { err };
262
+ }
@@ -0,0 +1,35 @@
1
+ export interface ErrorEntry {
2
+ code: string;
3
+ category: string;
4
+ http: number;
5
+ exit: number;
6
+ billed: string;
7
+ message: string;
8
+ fix: string;
9
+ }
10
+ export declare const ERRORS: readonly ErrorEntry[];
11
+ export declare const ERROR_BY_CODE: Readonly<Record<string, ErrorEntry>>;
12
+ export declare const CLIENT_ERRORS: readonly ErrorEntry[];
13
+ export declare const CLIENT_ERROR_BY_CODE: Readonly<Record<string, ErrorEntry>>;
14
+ export interface TierEntry {
15
+ name: string;
16
+ vcpus: number;
17
+ mem_gib: number;
18
+ disk_gib: number;
19
+ sellable: boolean;
20
+ per_second_usd: number;
21
+ }
22
+ export declare const TIERS: readonly TierEntry[];
23
+ export declare const BUILD_MAX_S = 3600;
24
+ export declare const PRICING: {
25
+ readonly vcpu_second_usd: 0.000014;
26
+ readonly gib_second_usd: 0.0000045;
27
+ readonly preemptible_vcpu_second_usd: 0.000007;
28
+ readonly preemptible_gib_second_usd: 0.00000225;
29
+ readonly egress_gib_usd: 0;
30
+ readonly storage_gib_month_usd: 0;
31
+ readonly min_billable_seconds: 1;
32
+ readonly granularity_seconds: 1;
33
+ readonly interim_interval_seconds: 60;
34
+ };
35
+ export declare const SANDBOX_STATES: readonly ["queued", "awaiting_capacity", "ready", "running", "paused", "ended"];
@@ -0,0 +1,307 @@
1
+ export const ERRORS = [
2
+ { code: "fork_failed", category: "env", http: 502, exit: 3, billed: "no",
3
+ message: "the sandbox could not be started",
4
+ fix: "Not billed. A run with a command is retried once automatically; otherwise re-run. If it repeats, re-verify the snapshot: `promigence snapshot verify {snapshot_id}`." },
5
+ { code: "start_timeout", category: "env", http: 502, exit: 3, billed: "no",
6
+ message: "the sandbox did not answer its first command within {deadline_ms} ms",
7
+ fix: "Not billed. A run with a command is retried once automatically; otherwise start it again. If it keeps happening, tell support@promigence.ai the run id." },
8
+ { code: "readiness_failed", category: "env", http: 502, exit: 3, billed: "no",
9
+ message: "the sandbox failed its readiness check",
10
+ fix: "Not billed: the sandbox was set aside before it was handed to you. A run with a command is retried once automatically; otherwise start it again. If it keeps failing, re-verify the snapshot: `promigence snapshot verify {snapshot_id}`." },
11
+ { code: "verify_too_slow", category: "env", http: 502, exit: 3, billed: "no",
12
+ message: "the snapshot's verify step took longer in this sandbox than its limit allows",
13
+ fix: "Not billed. A run with a command is retried once automatically; otherwise start it again. If it keeps happening, re-verify the snapshot: `promigence snapshot verify {snapshot_id}`." },
14
+ { code: "verify_each_failed", category: "env", http: 502, exit: 3, billed: "no",
15
+ message: "verify_each run failed in the fork (exit {exit_code}, digest {digest})",
16
+ fix: "Not billed. A run with a command is retried once automatically. If it repeats, the snapshot no longer reproduces: rebuild with `promigence snapshot create ...`." },
17
+ { code: "toolchain_mismatch", category: "env", http: 502, exit: 3, billed: "no",
18
+ message: "toolchain check `{argv}` in the fork gave digest {got}, the verified snapshot recorded {expected}",
19
+ fix: "The fork's toolchain differs from the verified snapshot; not billed. Re-run; if it repeats, rebuild the snapshot." },
20
+ { code: "sandbox_unresponsive", category: "env", http: 502, exit: 3, billed: "unless_ours",
21
+ message: "the sandbox stopped responding",
22
+ fix: "Billed for the time used, unless our side shows the cause was ours: then it is credited back (after a review if many are credited in one day), as the run report shows. Not retried automatically once your command has started. To run it again: `promigence run replay {run_id} --sandbox {sandbox_id}`. If you think the cause was ours, tell support@promigence.ai the run id." },
23
+ { code: "oom_within_tier", category: "env", http: 502, exit: 3, billed: "credited",
24
+ message: "the sandbox stopped on our side while within the tier's {tier_mib} MiB",
25
+ fix: "Our fault, not yours: credited back (at least the work lost since your last snapshot of this sandbox, up to 24 hours; a sandbox under 24 hours with no snapshot is not charged), after a review if many are credited in one day. Replay: `promigence run replay {run_id} --sandbox {sandbox_id}`." },
26
+ { code: "disk_full_within_tier", category: "env", http: 502, exit: 3, billed: "credited",
27
+ message: "the sandbox stopped on our side while within its {tier_disk_gib} GiB of disk",
28
+ fix: "Our fault, not yours: credited back (at least the work lost since your last snapshot of this sandbox, up to 24 hours; a sandbox under 24 hours with no snapshot is not charged), after a review if many are credited in one day. Replay: `promigence run replay {run_id} --sandbox {sandbox_id}`." },
29
+ { code: "sandbox_interrupted", category: "env", http: 502, exit: 3, billed: "credited",
30
+ message: "the sandbox was interrupted by a platform event",
31
+ fix: "Not caused by your work, and credited back: at least the work since your last snapshot of this sandbox, up to 24 hours; a sandbox under 24 hours with no snapshot is never charged. To run it again: `promigence run replay {run_id}`." },
32
+ { code: "integrity_mismatch", category: "env", http: 502, exit: 3, billed: "unless_ours",
33
+ message: "the environment differs from the verified snapshot at {path}",
34
+ fix: "Not billed when we confirm the stored snapshot itself differs at that path; otherwise (only this sandbox's copy changed, or the check could not be made) the time used is billed. To run it again: `promigence run replay {run_id} --sandbox {sandbox_id}`; if it happens again, rebuild the snapshot." },
35
+ { code: "egress_unavailable", category: "env", http: 502, exit: 3, billed: "unless_ours",
36
+ message: "the sandbox's outbound network was unavailable",
37
+ fix: "Not billed when we confirm the outage on our side, after a review if many are credited in one day; otherwise the time used is billed. To run it again: `promigence run replay {run_id}`." },
38
+ { code: "service_timeout", category: "env", http: 504, exit: 3, billed: "unless_ours",
39
+ message: "the service's own time limit ({deadline_ms} ms) was reached before your command's timeout",
40
+ fix: "When the cause was ours (our service restarted), it is credited back: at least the work since your last snapshot of this sandbox, up to 24 hours. Otherwise the time used is billed. For long commands, set `timeout_ms`. To run it again: `promigence run replay {run_id} --sandbox {sandbox_id}`." },
41
+ { code: "preempted", category: "preempt", http: 502, exit: 3, billed: "credited",
42
+ message: "the preemptible sandbox was stopped early, as preemptible runs can be",
43
+ fix: "Our doing, not yours: credited back (at least the work lost since your last snapshot of this sandbox, up to 24 hours; a sandbox under 24 hours with no snapshot is never charged). This run asked to be preemptible, which is priced below the standard rate for exactly this reason. To run it again: `promigence run replay {run_id} --sandbox {sandbox_id}`; or run it without `preemptible` to pay the standard rate and not be stopped early." },
44
+ { code: "verify_did_not_cover", category: "snapshot", http: 422, exit: 4, billed: "yes",
45
+ message: "`{path}` is missing but was not under a verified path; the snapshot's verify did not cover it",
46
+ fix: "Billed: the environment matched what `verify` checked. Broaden `verify` (or `setup`) so the path is produced and covered, then `promigence snapshot create ...`." },
47
+ { code: "grader_failed", category: "grader", http: 422, exit: 3, billed: "unless_ours",
48
+ message: "the grade could not be computed ({kind})",
49
+ fix: "Not a task failure. The time your grader ran is billed like the sandbox's own; a grade that failed on our side is not. Check that `grade.cmd` exits within `grade.timeout_ms` and that its output matches `grade.score` (exit | last_line_json | tap), then re-run." },
50
+ { code: "nonzero_exit", category: "task", http: 422, exit: 4, billed: "yes",
51
+ message: "command exited {exit_code}",
52
+ fix: "The environment was verified; the command failed. Inspect: `promigence exec output {exec_id}`." },
53
+ { code: "grade_not_passed", category: "task", http: 422, exit: 4, billed: "yes",
54
+ message: "the task completed and its grade did not pass (the grader exited {exit_code})",
55
+ fix: "Your grader failed the work; the task's command succeeded." },
56
+ { code: "task_timeout", category: "task", http: 422, exit: 4, billed: "yes",
57
+ message: "command exceeded timeout_ms={timeout_ms}",
58
+ fix: "Raise `--timeout` (billed per second used, so a longer timeout only costs what runs) or shorten the task." },
59
+ { code: "oom_over_tier", category: "task", http: 422, exit: 4, billed: "yes",
60
+ message: "the process was killed for exceeding the tier's {tier_mib} MiB of memory",
61
+ fix: "Rebuild the snapshot on a larger tier (`promigence snapshot create … --tier medium|large`; see `promigence agent-guide --section cost`) or reduce the task's memory." },
62
+ { code: "disk_over_tier", category: "task", http: 422, exit: 4, billed: "yes",
63
+ message: "the sandbox ran out of its {tier_disk_gib} GiB of disk",
64
+ fix: "Pick a larger tier or write less; the disk is sized to the tier quota." },
65
+ { code: "shutdown_by_task", category: "task", http: 422, exit: 4, billed: "yes",
66
+ message: "the sandbox shut itself down ({kind})",
67
+ fix: "Billed as the task's outcome: a command in the sandbox shut it down. Keep the task from doing that; if nothing in it should have, check what the agent ran." },
68
+ { code: "modified_by_task", category: "task", http: 422, exit: 4, billed: "yes",
69
+ message: "`{missing}` was removed or changed inside the sandbox; the snapshot's copy is intact",
70
+ fix: "Billed as the task's outcome: the sandbox started verified and something it ran deleted or changed `{path}`. Keep the task from modifying verified paths, or recreate what it needs first." },
71
+ { code: "cap_killed", category: "cap", http: 402, exit: 12, billed: "yes",
72
+ message: "sandbox killed when its accrued spend reached the spend cap ({spend_cap})",
73
+ fix: "The seconds it ran are billed, up to the cap. Raise `--cap` or `PATCH /sandboxes/:id` earlier." },
74
+ { code: "cap_exceeded", category: "cap", http: 409, exit: 5, billed: "no",
75
+ message: "quote {max_cost} exceeds remaining spend cap {remaining}",
76
+ fix: "Raise `--cap`, lower `--count`/`--timeout`, or pass `--allow-partial` to launch what fits." },
77
+ { code: "cap_paused", category: "cap", http: 402, exit: 5, billed: "no",
78
+ message: "sandbox {sandbox_id} is paused: its run reached its spend cap ({spend_cap})",
79
+ fix: "Its files and state are kept, and paused time is not billed. Raise the run's cap to go on: `promigence sandbox resume {sandbox_id} --cap <usd>` (`spend_cap` on POST /v1/sandboxes/{sandbox_id}/resume). Or end it: `promigence sandbox kill {sandbox_id}`." },
80
+ { code: "credits_paused", category: "cap", http: 402, exit: 5, billed: "no",
81
+ message: "sandbox {sandbox_id} is paused: the organization's credits ran out",
82
+ fix: "Its files and state are kept, and paused time is not billed. Add a card to go on (owners: `promigence billing card`; members ask an owner), then resume it: `promigence sandbox resume {sandbox_id}`. Or end it: `promigence sandbox kill {sandbox_id}`." },
83
+ { code: "aborted_by_client", category: "other", http: 200, exit: 130, billed: "yes",
84
+ message: "sandbox killed by the client",
85
+ fix: "Nothing to fix; billed for the seconds used." },
86
+ { code: "stopped_by_support", category: "other", http: 200, exit: 12, billed: "unless_ours",
87
+ message: "Stopped by Promigence support: {reason}",
88
+ fix: "Billed for the seconds it ran, as a kill is, unless support found the cause was on our side; then that time is credited back. Questions: tell support@promigence.ai the sandbox id." },
89
+ { code: "expired", category: "other", http: 200, exit: 12, billed: "yes",
90
+ message: "sandbox timeout reached (counted from hand-off)",
91
+ fix: "Raise `--timeout` if the task needs longer." },
92
+ { code: "not_started", category: "other", http: 200, exit: 12, billed: "no",
93
+ message: "sandbox not started: outside the spend cap",
94
+ fix: "Raise `--cap`; with `--allow-partial` only what fits is launched." },
95
+ { code: "superseded", category: "other", http: 200, exit: 0, billed: "no",
96
+ message: "attempt 1 superseded by a successful retry",
97
+ fix: "Nothing to fix; attempt 1 is unbilled." },
98
+ { code: "usage", category: "other", http: 400, exit: 2, billed: "no",
99
+ message: "{detail}",
100
+ fix: "{detail}. See `promigence {command} --help`." },
101
+ { code: "internal", category: "other", http: 500, exit: 1, billed: "no",
102
+ message: "internal error",
103
+ fix: "Not your fault. Re-run; if it repeats, tell support@promigence.ai the run or sandbox id and the time." },
104
+ { code: "auth", category: "other", http: 401, exit: 7, billed: "no",
105
+ message: "missing or invalid API key",
106
+ fix: "Set PROMIGENCE_API_KEY or run `promigence auth login --from-env VAR`. No key yet: `promigence login` (sign in) or https://promigence.ai." },
107
+ { code: "forbidden", category: "other", http: 403, exit: 7, billed: "no",
108
+ message: "{detail}",
109
+ fix: "Do what the message names: sign in (`promigence login`), use a full-access key (`promigence keys create`) or one from that org, or ask an owner." },
110
+ { code: "not_found", category: "other", http: 404, exit: 8, billed: "no",
111
+ message: "{kind} `{id}` not found",
112
+ fix: "Check the id; aliases resolve in your org first, then public snapshots (`promigence examples`)." },
113
+ { code: "unreachable", category: "other", http: 503, exit: 9, billed: "no",
114
+ message: "cannot reach {url}",
115
+ fix: "Retry in a moment. If the API answered this, the fault is ours: if it repeats, email support@promigence.ai with the sandbox or run id. If the API itself did not answer, check PROMIGENCE_API_URL and your connection." },
116
+ { code: "rate_limited", category: "other", http: 429, exit: 10, billed: "no",
117
+ message: "rate limited by {host}; retry after {retry_after_s} s",
118
+ fix: "Wait `Retry-After` seconds, then retry. If the limit is an image registry's, not this API's, a `registry_secret` holding your own login for it usually raises it. Otherwise lower concurrency (see `GET /me` limits)." },
119
+ { code: "timeout", category: "other", http: 504, exit: 11, billed: "no",
120
+ message: "wait of {wait_timeout} expired; nothing was killed",
121
+ fix: "Run the id-based command: `{next}`." },
122
+ { code: "not_verified", category: "other", http: 409, exit: 6, billed: "no",
123
+ message: "snapshot {snapshot_id} is not verified (build {build_id}: {state})",
124
+ fix: "Wait for the build: `promigence snapshot status {build_id} --wait`." },
125
+ { code: "snapshot_incompatible", category: "other", http: 409, exit: 6, billed: "no",
126
+ message: "snapshot {snapshot_id} can no longer run on the platform",
127
+ fix: "Nothing was started or billed. Rebuild it from the same source: POST /v1/snapshots (`promigence snapshot create`)." },
128
+ { code: "storage_limit_reached", category: "other", http: 409, exit: 5, billed: "no",
129
+ message: "{detail}",
130
+ fix: "Nothing was stored or charged, and nothing already stored was removed: delete what you no longer need, or move to a plan that keeps more." },
131
+ { code: "resume_unavailable", category: "env", http: 503, exit: 3, billed: "no",
132
+ message: "sandbox {sandbox_id} is safe and still paused; it could not be resumed right now",
133
+ fix: "Your files are kept and nothing was billed. Retry in a minute. If it keeps happening, email support@promigence.ai with the sandbox id." },
134
+ { code: "sandbox_unreachable", category: "env", http: 503, exit: 3, billed: "no",
135
+ message: "sandbox {sandbox_id} could not be reached just now; nothing was changed",
136
+ fix: "Not billed for this call, and the sandbox is as it was. Retry in a few seconds. If it keeps happening, email support@promigence.ai with the sandbox id." },
137
+ { code: "capacity_busy", category: "env", http: 503, exit: 3, billed: "no",
138
+ message: "no capacity free right now",
139
+ fix: "Not billed, and nothing was started. Nothing was free in time: start it again in a few minutes, or lower `--count` to need fewer at once." },
140
+ { code: "region_at_capacity", category: "env", http: 503, exit: 3, billed: "no",
141
+ message: "capacity is full right now",
142
+ fix: "Not billed, and nothing was started. Retry shortly, or lower `--count`." },
143
+ { code: "builder_unavailable", category: "env", http: 503, exit: 3, billed: "no",
144
+ message: "new snapshots cannot be built right now",
145
+ fix: "Not billed, and nothing was stored. Nothing here can build at all, so this is not a busy queue and does not clear itself by waiting, and a smaller run does not help. Snapshots you have already built still run, so re-use one (`promigence snapshot list`). If you asked for a specific CPU, drop that and retry; otherwise retry shortly, and tell support@promigence.ai the time if it keeps happening." },
146
+ { code: "builder_busy", category: "env", http: 503, exit: 3, billed: "no",
147
+ message: "snapshot builds are backed up; retry after {retry_after_s} s",
148
+ fix: "Not billed, and nothing was stored. Other builds are ahead of this one: submit it again in {retry_after_s} s. Builds already accepted keep their place in the queue and finish on their own (`promigence snapshot status <build_id> --wait`)." },
149
+ { code: "overloaded", category: "env", http: 503, exit: 3, billed: "no",
150
+ message: "the API is at capacity; retry in {retry_after_s} s",
151
+ fix: "Not billed, and nothing was started. Send the same request again in {retry_after_s} s; the SDKs and the CLI do this for you." },
152
+ { code: "tier_unavailable", category: "env", http: 503, exit: 3, billed: "no",
153
+ message: "the {tier} tier ({vcpus} vCPU / {mem_gib} GiB) is not available yet",
154
+ fix: "Not billed. Use a smaller tier (`promigence snapshot create … --tier`; a fork runs on its snapshot's), or write to support@promigence.ai to have {tier} enabled for your account." },
155
+ { code: "snapshot_unavailable", category: "env", http: 409, exit: 3, billed: "no",
156
+ message: "snapshot {snapshot_id} is no longer available: it could not be saved",
157
+ fix: "Not billed, and nothing was started. It cannot be started again: take a new snapshot of a running sandbox (`promigence sandbox snapshot <sandbox_id>`) or build it again (`promigence snapshot create ...`), then remove this one: `promigence snapshot delete {snapshot_id}`." },
158
+ { code: "capacity_limit", category: "env", http: 409, exit: 3, billed: "no",
159
+ message: "{requested} {tier} sandboxes at once is more than one run can start at once; at most {max_at_once}",
160
+ fix: "Not billed; nothing started. Run at most {max_at_once} at once (lower `--count`), or use a smaller tier." },
161
+ { code: "build_timeout", category: "other", http: 422, exit: 4, billed: "yes",
162
+ message: "the build ran past its {limit_min}-minute limit",
163
+ fix: "Nothing was stored; the {limit_min} minutes it ran are billed. Shorten `setup` (at most 64 steps, {limit_min} minutes in all) or bake the slow part into the image." },
164
+ { code: "dockerfile_build_failed", category: "other", http: 400, exit: 2, billed: "yes",
165
+ message: "your image could not be built from the Dockerfile: {detail}",
166
+ fix: "Nothing was stored; the time the build ran is billed. Fix the Dockerfile (the lines above are the end of your own build output) and run `promigence snapshot create --dockerfile PATH ...` again." },
167
+ { code: "image_unresolvable", category: "other", http: 422, exit: 2, billed: "no",
168
+ message: "`{image}` could not be resolved to a digest: {detail}",
169
+ fix: "Nothing was stored and nothing was billed. Check the name and tag; a private image needs `registry_secret` naming a stored secret that holds `user:password` (`promigence secrets set`). You can also pass the image already pinned as NAME@sha256:<digest>." },
170
+ { code: "registry_unavailable", category: "env", http: 503, exit: 3, billed: "no",
171
+ message: "`{image}` could not be resolved to a digest because its registry did not answer usably: {detail}",
172
+ fix: "Not billed, and nothing was stored. Your image is not at fault: submit it again in {retry_after_s} s. Snapshots you have already built from it still run (`promigence snapshot list`)." },
173
+ { code: "enoent", category: "other", http: 404, exit: 8, billed: "no",
174
+ message: "`{argv0}` not found in the sandbox",
175
+ fix: "Check the command name; install the program in the image or in a setup step; for a shell builtin or a pipeline, run it through a shell: `-- sh -c '...'`." },
176
+ { code: "trial_credits_exhausted", category: "cap", http: 402, exit: 5, billed: "no",
177
+ message: "trial credits left ({remaining}) do not cover this ({needed})",
178
+ fix: "Add a card to keep going (owners: `promigence billing card`, or POST /v1/billing/checkout; members ask an owner). Remaining credits are used first; running sandboxes finish." },
179
+ { code: "credit_unclaimed", category: "other", http: 402, exit: 5, billed: "no",
180
+ message: "this account has free credit waiting to be claimed",
181
+ fix: "Claim it in your browser: `promigence credits claim` (owners; members ask an owner). Or add a card: `promigence billing card`. Nothing was started or charged." },
182
+ { code: "setup_required", category: "other", http: 403, exit: 7, billed: "no",
183
+ message: "finish setting up your account before starting new work",
184
+ fix: "Open {setup_url} and answer the setup questions (under a minute), then run this again. Nothing was started or charged." },
185
+ { code: "card_required", category: "other", http: 402, exit: 5, billed: "no",
186
+ message: "a card is required for new work since {effective_at}",
187
+ fix: "Add a card (owners: `promigence billing card`, or POST /v1/billing/checkout; members ask an owner). Your trial credits are kept and used first; reads and results stay available." },
188
+ { code: "billing_unavailable", category: "other", http: 503, exit: 5, billed: "no",
189
+ message: "card payments are not open yet",
190
+ fix: "Nothing was charged. Your trial credits are kept and used first; for more credits, email support@promigence.ai." },
191
+ { code: "concurrency_limit", category: "other", http: 409, exit: 5, billed: "no",
192
+ message: "{live} live + {requested} requested sandboxes is over your limit of {limit}",
193
+ fix: "Wait for sandboxes to end or lower `--count` (`--allow-partial` covers the spend cap only); a retry of the same request fails the same way. Trial orgs get {trial_limit}; to raise it, email support@promigence.ai." },
194
+ { code: "egress_cap_reached", category: "other", http: 403, exit: 5, billed: "no",
195
+ message: "monthly data-out cap reached: {used_gb} of {cap_gb} GB",
196
+ fix: "Use `--network none` (still allowed) or wait for the 1st (UTC). For more data out a month, email support@promigence.ai." },
197
+ { code: "project_cap_reached", category: "cap", http: 403, exit: 5, billed: "no",
198
+ message: "project {project} has {remaining} of its {limit} monthly cap left; this needs {needed}",
199
+ fix: "Ask for less (`--count`, `--cap`, a shorter extension), wait for the 1st (UTC), or have an owner raise it: `promigence project cap {project} <usd>`." },
200
+ { code: "spend_limit_reached", category: "cap", http: 402, exit: 5, billed: "no",
201
+ message: "today's spend limit {limit} has {remaining} left; this needs {needed}",
202
+ fix: "Running sandboxes finish. The limit resets at 00:00 UTC and grows with each paid invoice; ask for less, or email support@promigence.ai." },
203
+ { code: "billing_hold", category: "other", http: 402, exit: 5, billed: "no",
204
+ message: "new work is on hold: {reason}",
205
+ fix: "Running sandboxes finish. Owners: update the card with `promigence billing portal`; the hold lifts once the invoice is paid. For a disputed payment, write to support@promigence.ai." },
206
+ { code: "tier_over_plan", category: "other", http: 403, exit: 2, billed: "no",
207
+ message: "the {tier} tier ({vcpus} vCPU) is over the {limit} vCPU per-sandbox limit of your {plan} plan",
208
+ fix: "Use a tier of at most {limit} vCPU (`promigence snapshot create … --tier {max_tier}` is the largest; a fork runs on its snapshot's), or move to a plan that allows it: `promigence billing portal`." },
209
+ { code: "network_host_refused", category: "other", http: 403, exit: 9, billed: "no",
210
+ message: "{host} is not on this sandbox's allowed list, so the connection was refused",
211
+ fix: "Add it when you start the sandbox — `--allow {host}` — or drop `--allow` to let the sandbox reach anything. `promigence sandbox network <id>` lists everything that has been refused." },
212
+ { code: "network_policy_unsupported", category: "env", http: 502, exit: 3, billed: "no",
213
+ message: "this sandbox asked to reach only {allow}, and that could not be applied",
214
+ fix: "Nothing ran and nothing was billed: the sandbox was discarded rather than started without the restriction you asked for. Re-run; if it repeats, tell support@promigence.ai the run id." },
215
+ { code: "secrets_in_snapshot", category: "other", http: 409, exit: 2, billed: "no",
216
+ message: "sandbox {sandbox_id} was given a secret's value, so a snapshot of it can contain that value",
217
+ fix: "To take it anyway, pass `force: true` (`promigence sandbox snapshot {sandbox_id} --force`): that snapshot, and every sandbox started from it, can then contain the secret. Otherwise snapshot a sandbox that was never given a secret, and name the secret on the runs you start from it." },
218
+ { code: "secrets_unavailable", category: "env", http: 503, exit: 3, billed: "no",
219
+ message: "secrets cannot be used right now",
220
+ fix: "Not billed, and nothing that names a secret was started. Runs, commands and terminals that name no secret are unaffected, and stored secrets can still be listed and deleted. Retry shortly; if it keeps happening, tell support@promigence.ai the time." },
221
+ { code: "secret_binding_unsupported", category: "env", http: 502, exit: 3, billed: "no",
222
+ message: "a secret bound to a host could not be set up for this sandbox",
223
+ fix: "Nothing ran, nothing was billed, and the value never entered the sandbox. Re-run; if it repeats, tell support@promigence.ai the run id." },
224
+ { code: "idempotency_key_reused", category: "other", http: 409, exit: 2, billed: "no",
225
+ message: "this Idempotency-Key was used for a different request",
226
+ fix: "Nothing was started. Use a new key for a new request; send the original request again to get its original answer." },
227
+ { code: "idempotency_key_in_use", category: "env", http: 409, exit: 3, billed: "no",
228
+ message: "a request with this Idempotency-Key is still running",
229
+ fix: "Not billed; nothing new was started. Send the same request again in {retry_after_s} s for the first one's answer; the SDKs do this for you." },
230
+ { code: "repo_credentials_not_supported", category: "other", http: 400, exit: 2, billed: "no",
231
+ message: "credentials in repository URLs are not accepted ({field})",
232
+ fix: "Nothing was built or billed. A repository URL never carries a credential. For a private repository, connect its host once for your organization (`promigence github connect` or `promigence gitlab connect`) and name it as `--repo owner/name` (`--repo gitlab:group/project`); a public one is named by its plain https:// URL, with no user name, password, token, query string or fragment in it." },
233
+ { code: "account_exists", category: "other", http: 409, exit: 7, billed: "no",
234
+ message: "this email address has an account that signs in with {sign_in_with}",
235
+ fix: "Nothing was created. Sign in with {sign_in_with} instead: `{sign_in_command}`. If the browser signs you in with the method you just used, open the sign-in link in a private window. If you did not create that account, write to support@promigence.ai." },
236
+ { code: "invite_invalid", category: "other", http: 403, exit: 7, billed: "no",
237
+ message: "this invite code is not valid",
238
+ fix: "Nothing was created. Check the code and try `promigence signup` again, or ask the person who invited you for a new code." },
239
+ { code: "invite_required", category: "other", http: 403, exit: 7, billed: "no",
240
+ message: "new accounts need an invite code right now",
241
+ fix: "Nothing was created. Run `promigence signup` and enter your invite code when asked. If you already have an account, sign in with the method you used before (`promigence login`)." },
242
+ { code: "key_expired", category: "other", http: 401, exit: 7, billed: "no",
243
+ message: "this API key expired at {expired_at}",
244
+ fix: "Create a new key (`promigence keys create`, or sign in again with `promigence login`) and replace this one wherever it is used." },
245
+ { code: "account_blocked", category: "other", http: 401, exit: 7, billed: "no",
246
+ message: "this account is blocked",
247
+ fix: "Write to support@promigence.ai to have it reviewed." },
248
+ ];
249
+ export const ERROR_BY_CODE = Object.fromEntries(ERRORS.map((e) => [e.code, e]));
250
+ export const CLIENT_ERRORS = [
251
+ { code: "invalid_argument", category: "other", http: 0, exit: 2, billed: "no",
252
+ message: "an argument the SDK refused before sending it",
253
+ fix: "Nothing was sent or billed. The message names the argument and the form it takes: change it and call again. From the CLI, `promigence <command> --help` lists every flag." },
254
+ { code: "unsupported", category: "other", http: 0, exit: 2, billed: "no",
255
+ message: "not available in this version or on this deployment",
256
+ fix: "Nothing was sent or billed. The fix in the error names what to use instead." },
257
+ { code: "not_released", category: "other", http: 0, exit: 1, billed: "no",
258
+ message: "not released in this version",
259
+ fix: "Nothing was sent or billed. Update the CLI or SDK once a release implements it (support@promigence.ai has the latest)." },
260
+ { code: "task_failed", category: "task", http: 0, exit: 4, billed: "yes",
261
+ message: "the command exited non-zero (the SDK's CommandExitError)",
262
+ fix: "The environment was verified and the command failed: read stdout and stderr on the error, or pass `throwOnExit: false` to get the result instead. A run's report calls the same failure `nonzero_exit`." },
263
+ { code: "env_failed", category: "env", http: 0, exit: 3, billed: "no",
264
+ message: "the sandbox ended before hand-over",
265
+ fix: "Ours, not billed. The run's report names the failure's own code (`promigence run report RUN`); start the sandbox again." },
266
+ { code: "snapshot_rejected", category: "other", http: 0, exit: 6, billed: "unless_ours",
267
+ message: "a build guard refused it; nothing was stored",
268
+ fix: "The time the build ran is billed, unless it ended on our side. Read the build log (`promigence snapshot status BUILD --log 80`): the guard named in the error says what to change (verify exited non-zero, a setup step failed, a time or size bound), then build again." },
269
+ { code: "build_failed", category: "env", http: 0, exit: 3, billed: "no",
270
+ message: "the build could not finish; nothing was stored",
271
+ fix: "Not charged. Build again; if it repeats, email support@promigence.ai with the build id." },
272
+ { code: "service_restart", category: "env", http: 0, exit: 3, billed: "no",
273
+ message: "a service restart stopped the command while its output was streaming",
274
+ fix: "Not billed: the time the command ran is credited back. The sandbox kept running; the command may have done part of its work before it stopped: run it again if that is safe." },
275
+ { code: "not_connected", category: "other", http: 0, exit: 7, billed: "no",
276
+ message: "the connection request ended without connecting anything",
277
+ fix: "Nothing was connected. Do what the message names, then run the connect command again; `promigence github status` (or `gitlab status`) lists what is connected." },
278
+ { code: "snapshot_failed", category: "snapshot", http: 0, exit: 4, billed: "unless_ours",
279
+ message: "a build ended with no snapshot, or the snapshot did not hold",
280
+ fix: "A build: read its log (`promigence snapshot status BUILD --log 80`), fix what it names, build again. A run: the sandbox's own failure code says what (usually `verify_did_not_cover`: broaden `verify`)." },
281
+ ];
282
+ export const CLIENT_ERROR_BY_CODE = Object.fromEntries(CLIENT_ERRORS.map((e) => [e.code, e]));
283
+ export const TIERS = [
284
+ { name: "xsmall", vcpus: 1, mem_gib: 1, disk_gib: 10, sellable: true, per_second_usd: 0.0000185 },
285
+ { name: "small", vcpus: 2, mem_gib: 4, disk_gib: 10, sellable: true, per_second_usd: 0.000046 },
286
+ { name: "medium", vcpus: 4, mem_gib: 16, disk_gib: 20, sellable: true, per_second_usd: 0.000128 },
287
+ { name: "large-16", vcpus: 8, mem_gib: 16, disk_gib: 40, sellable: true, per_second_usd: 0.000184 },
288
+ { name: "large", vcpus: 8, mem_gib: 32, disk_gib: 40, sellable: true, per_second_usd: 0.000256 },
289
+ { name: "xlarge", vcpus: 16, mem_gib: 32, disk_gib: 80, sellable: true, per_second_usd: 0.000368 },
290
+ { name: "2xlarge", vcpus: 32, mem_gib: 64, disk_gib: 160, sellable: true, per_second_usd: 0.000736 },
291
+ { name: "bench-8x8", vcpus: 8, mem_gib: 8, disk_gib: 20, sellable: false, per_second_usd: 0 },
292
+ { name: "bench-8x16", vcpus: 8, mem_gib: 16, disk_gib: 20, sellable: false, per_second_usd: 0 },
293
+ { name: "bench-4x8", vcpus: 4, mem_gib: 8, disk_gib: 40, sellable: false, per_second_usd: 0 },
294
+ ];
295
+ export const BUILD_MAX_S = 3600;
296
+ export const PRICING = {
297
+ vcpu_second_usd: 0.000014,
298
+ gib_second_usd: 0.0000045,
299
+ preemptible_vcpu_second_usd: 0.000007,
300
+ preemptible_gib_second_usd: 0.00000225,
301
+ egress_gib_usd: 0,
302
+ storage_gib_month_usd: 0,
303
+ min_billable_seconds: 1,
304
+ granularity_seconds: 1,
305
+ interim_interval_seconds: 60,
306
+ };
307
+ export const SANDBOX_STATES = ["queued", "awaiting_capacity", "ready", "running", "paused", "ended"];