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,285 @@
1
+ /** Promigence SDK — constants, error hierarchy and shared types. */
2
+ export declare const VERSION = "0.1.0-beta.12";
3
+ export declare const DOCS_URL = "https://promigence.ai";
4
+ /** The error reference; each code is an anchor on it (the API's `docs` link has the same form). */
5
+ export declare const ERRORS_DOCS_URL = "https://www.promigence.ai/docs/errors";
6
+ export declare const DEFAULT_API_URL = "https://api.promigence.ai/v1";
7
+ /** Where to write about a key. A key is self-serve: `promigence login` signs up or in and stores one. */
8
+ export declare const KEY_CONTACT = "support@promigence.ai";
9
+ /** Every bounded wait defaults to this; below agent tool timeouts. */
10
+ export declare const WAIT_TIMEOUT_MS = 100000;
11
+ /**
12
+ * `Sandbox.create({ image })` bounds the first build of an image by this (15 min): pull +
13
+ * flatten + boot is minutes, not the 100 s a fork waits. Expiry cancels nothing.
14
+ */
15
+ export declare const IMAGE_BUILD_TIMEOUT_MS: number;
16
+ /**
17
+ * The most one new snapshot build of the default tier can cost at the list prices this SDK was
18
+ * built with, in USD: its time limit (an hour) at that tier's per-second rate. A build is billed per
19
+ * second for the time it runs; reusing or joining an identical build is free. Prices change: the
20
+ * live figure is `client.pricing()`'s `rates.build_usd` (this key's organization's), and a build's
21
+ * own arrives as `build_price` in the `POST /snapshots` answer. This is only the fallback when the
22
+ * API cannot be asked.
23
+ */
24
+ export declare const IMAGE_BUILD_LIST_PRICE = 0.1656;
25
+ /** Inline output budget for an exec before `truncated` + `_ref`. */
26
+ export declare const MAX_OUTPUT_BYTES_DEFAULT: number;
27
+ /** One request of a `files.put`. **Not a file-size limit** — `put` loops. */
28
+ export declare const FILE_PUT_CHUNK_BYTES: number;
29
+ export interface PromigenceErrorInit {
30
+ code: string;
31
+ message: string;
32
+ fix: string;
33
+ docs?: string;
34
+ exitCode?: number;
35
+ /** HTTP status, when the error came from the API. */
36
+ status?: number;
37
+ /** `request_id` header, when present. */
38
+ requestId?: string;
39
+ /** `Retry-After`, in ms, when the answer carried one. */
40
+ retryAfterMs?: number;
41
+ /** The API error's `category`: `env` (ours; credited back when our side shows the cause), `task`, `cap`, `other`, ... */
42
+ category?: string;
43
+ /** The API error's `retryable`: nothing ran and the same request, sent again as is, can succeed. */
44
+ retryable?: boolean;
45
+ }
46
+ /** What a caller reads instead: a fact about this beta, not a mistake of theirs. */
47
+ export declare const PREVIEWS_UNAVAILABLE = "preview URLs are not available in this beta yet";
48
+ export declare function previewsFix(sandboxId?: string, port?: string | number): string;
49
+ /**
50
+ * A `fix` that opens by repeating the message says only what it adds: the API's `usage` fix is
51
+ * "{detail}. See `promigence … --help`.", and a client that prints both would say the sentence
52
+ * twice. A fix that is nothing but the message says what to do in general.
53
+ */
54
+ export declare function fixBeyondMessage(message: string, fix: string): string;
55
+ export declare class PromigenceError extends Error {
56
+ readonly code: string;
57
+ readonly fix: string;
58
+ readonly docs: string;
59
+ /**
60
+ * On [`CommandExitError`] this is overridden with the *command's* exit code — see the note
61
+ * there — so anything that needs the CLI's number must read [`cliExit`], never this.
62
+ */
63
+ readonly exitCode: number;
64
+ /** The CLI's exit code, always. Equal to `exitCode` except on [`CommandExitError`]. */
65
+ readonly cliExit: number;
66
+ readonly guide: string;
67
+ readonly status: number | undefined;
68
+ readonly requestId: string | undefined;
69
+ /**
70
+ * The server's `Retry-After`, in ms, on ANY error that carried one: a 429, and also a 503 env
71
+ * failure that clears by waiting (`builder_busy`, `registry_unavailable`). `undefined` when the
72
+ * answer named no time.
73
+ */
74
+ readonly retryAfterMs: number | undefined;
75
+ /**
76
+ * Whose failure it was, as the API said (`category` in the error): `env` is ours and never
77
+ * billed, `task` your command's, `cap` a spend limit, `other` a refusal of the request. New
78
+ * values may appear. `undefined` when the answer did not say (an error the SDK made itself).
79
+ */
80
+ readonly category: string | undefined;
81
+ /**
82
+ * The API's `retryable`: `true` when nothing of yours ran and the same request, sent again
83
+ * unchanged (after `retryAfterMs` when set), can succeed. `false` when something must change
84
+ * first, or when the request may already have done its work. `undefined` when the answer did
85
+ * not say. The SDK's own retries do not depend on it.
86
+ */
87
+ readonly retryable: boolean | undefined;
88
+ constructor(init: PromigenceErrorInit);
89
+ toJSON(): {
90
+ retryable?: boolean;
91
+ category?: string;
92
+ request_id?: string;
93
+ code: string;
94
+ message: string;
95
+ fix: string;
96
+ docs: string;
97
+ guide: string;
98
+ };
99
+ }
100
+ /** Bad arguments (e.g. an unknown template, a missing spend cap). exit 2 */
101
+ export declare class InvalidArgumentError extends PromigenceError {
102
+ /**
103
+ * `code` defaults to `invalid_argument` — what the SDK raises for a bad argument it catches
104
+ * itself — but the API's own `usage` maps to this class too, and a client that renames a
105
+ * code the caller then has to look up is a client the error index cannot help. So the wire
106
+ * code is carried through when there is one.
107
+ */
108
+ constructor(message: string, fix: string, code?: string);
109
+ }
110
+ /** A call this version does not implement; names the alternative in `fix`. exit 2 */
111
+ export declare class UnsupportedError extends PromigenceError {
112
+ constructor(feature: string, alternative: string);
113
+ /**
114
+ * A [`PreviewsUnavailableError`] is one too, as Python's class is (it subclasses both there):
115
+ * TS has one parent, so it extends `InvalidArgumentError` (what it was raised as before) and
116
+ * this check admits it. Only on `UnsupportedError` itself; a subclass checks as usual.
117
+ */
118
+ static [Symbol.hasInstance](x: unknown): boolean;
119
+ }
120
+ /** True when an API message is the deployment's "previews are not enabled" answer. */
121
+ export declare function previewsOff(message: string): boolean;
122
+ export declare class PreviewsUnavailableError extends InvalidArgumentError {
123
+ constructor(sandboxId?: string, port?: string | number);
124
+ }
125
+ /** The environment failed (our fault, never the task's). exit 3 */
126
+ export declare class EnvFailedError extends PromigenceError {
127
+ constructor(code: string, message: string, fix: string);
128
+ }
129
+ /**
130
+ * `commands.run` foreground with non-zero exit (opt out with `throwOnExit: false`). CLI exit 4.
131
+ *
132
+ * **`exitCode` is the COMMAND's exit code**, not the CLI's. That is a deliberate divergence from
133
+ * every other error in this file, and it is the one place `cliExit` exists for.
134
+ *
135
+ * The reason is compatibility, and it is a correctness bug rather than a nicety:
136
+ * `CommandExitError implements CommandResult`, so a call site reads
137
+ *
138
+ * ```ts
139
+ * catch (e) { if (e.exitCode === 1) retry(); }
140
+ * ```
141
+ *
142
+ * and means the command's code. We used to put `4` there — the CLI's `task_failed` code — and
143
+ * hide the real one on `exitCodeOfCommand`. That does not throw, it does not warn: it silently
144
+ * answers a different question, which is the worst failure mode a compatibility shim has.
145
+ * `exitCodeOfCommand` stays as an alias so existing Promigence-native callers keep working.
146
+ */
147
+ export declare class CommandExitError extends PromigenceError implements Pick<CommandResult, "stdout" | "stderr"> {
148
+ /** Alias of `exitCode`, kept for callers written against the pre-compat shape. */
149
+ readonly exitCodeOfCommand: number;
150
+ readonly stdout: string;
151
+ readonly stderr: string;
152
+ readonly exitCode: number;
153
+ constructor(result: CommandResult);
154
+ }
155
+ /** Quote/PATCH above the spend cap; nothing started. exit 5 */
156
+ export declare class SpendCapError extends PromigenceError {
157
+ /**
158
+ * `cap_exceeded` (refused before anything started, nothing billed) and `cap_killed` (stopped
159
+ * part-way, billed for the seconds it used) are the same class and are NOT the same outcome.
160
+ * Collapsing both to `cap_exceeded` told a caller nothing had been charged when something had.
161
+ */
162
+ constructor(message: string, fix?: string, code?: string);
163
+ }
164
+ /** Fork/run against a snapshot whose build is not verified. exit 6 */
165
+ export declare class NotVerifiedError extends PromigenceError {
166
+ constructor(message: string, fix?: string);
167
+ }
168
+ /** Missing or invalid API key. exit 7 */
169
+ export declare class AuthError extends PromigenceError {
170
+ constructor(message?: string, fix?: string);
171
+ }
172
+ /** Snapshot / run / sandbox not found. exit 8 */
173
+ export declare class NotFoundError extends PromigenceError {
174
+ constructor(message: string, fix?: string);
175
+ }
176
+ /** API unreachable (connection refused, DNS, 5xx after retries). exit 9 */
177
+ export declare class UnreachableError extends PromigenceError {
178
+ constructor(message: string, fix?: string);
179
+ }
180
+ /** 429 with Retry-After. exit 10 */
181
+ export declare class RateLimitError extends PromigenceError {
182
+ constructor(message: string, retryAfterMs?: number);
183
+ }
184
+ /** A bounded wait expired. Nothing is killed; `fix` names the id-based command. exit 11 */
185
+ export declare class TimeoutError extends PromigenceError {
186
+ /** The sandbox an expired wait was for, when it was for one: re-attach or kill it by this. */
187
+ readonly sandboxId: string | undefined;
188
+ /** That sandbox's run. */
189
+ readonly runId: string | undefined;
190
+ constructor(message: string, fix: string, ids?: {
191
+ sandboxId?: string;
192
+ runId?: string;
193
+ });
194
+ }
195
+ /**
196
+ * A service update may stop a command that was running while its output was streaming to you
197
+ * (`execStream`, `commands.run` with output callbacks); the time it ran is credited back, and the
198
+ * sandbox keeps running. `retryable` is `false`: the command may have done part of its work before
199
+ * it stopped, so run it again only if that is safe. exit 3
200
+ */
201
+ export declare class ServiceRestartError extends PromigenceError {
202
+ constructor(message: string, fix: string);
203
+ }
204
+ /** An API error with no more specific class (5xx, unknown code). exit from the table. */
205
+ export declare class ApiError extends PromigenceError {
206
+ }
207
+ /** Placeholder surface that is not implemented in this release. exit 1 */
208
+ export declare class NotReleasedError extends PromigenceError {
209
+ constructor(what: string);
210
+ }
211
+ export declare const EXIT_BY_CODE: Readonly<Record<string, number>>;
212
+ export declare function exitForCode(code: string): number;
213
+ export type Tier = "xsmall" | "small" | "medium" | "large-16" | "large" | "xlarge" | "2xlarge";
214
+ /**
215
+ * What a sandbox may reach.
216
+ *
217
+ * - `"egress"` (default) — anything, minus the always-on outbound mail block.
218
+ * - `"none"` — nothing.
219
+ * - `{ allow: [...] }` — these destinations and nothing else. `"github.com"` is that host
220
+ * exactly; `"*.npmjs.org"` is anything under `npmjs.org` but not `npmjs.org` itself; a literal
221
+ * IPv4 address is permitted as written. Anything else is refused, and the sandbox's
222
+ * `network` view names every host it asked for and did not get.
223
+ *
224
+ * Read what an allowed list does and does not promise before you rely on it: it is spelled out
225
+ * on `SandboxForkOpts.allowHosts`.
226
+ */
227
+ export type NetworkMode = "none" | "egress" | {
228
+ allow: string[];
229
+ };
230
+ /**
231
+ * `compute` makes memory-heavy work in sandboxes of 15 GiB and more run faster — a few percent on a cold build — and makes starting many of them at once slower. It changes nothing on smaller sandboxes. Default: `start`.
232
+ */
233
+ export type OptimizeFor = "start" | "compute";
234
+ export interface CommandResult {
235
+ exitCode: number;
236
+ stdout: string;
237
+ stderr: string;
238
+ truncated?: boolean;
239
+ /** `exec_id`, for `promigence exec output <exec_id>` / `GET /sandboxes/:id/execs/:exec_id`. */
240
+ execId?: string;
241
+ }
242
+ export interface CommandRunOpts {
243
+ cwd?: string;
244
+ envs?: Record<string, string>;
245
+ user?: string;
246
+ /**
247
+ * The command's own bound. `0` means no bound of its own: a background command
248
+ * then lives as long as the sandbox, a foreground one is bounded by the sandbox's timeout
249
+ * (or the default 15 minutes).
250
+ */
251
+ timeoutMs?: number;
252
+ /** Throw `CommandExitError` on non-zero exit (default true). */
253
+ throwOnExit?: boolean;
254
+ /** Inline output budget; `truncated` beyond it (default 64 KiB). */
255
+ maxOutputBytes?: number;
256
+ /** Start it and return a `CommandHandle` now (`wait()`, `kill()`, output callbacks). */
257
+ background?: boolean;
258
+ }
259
+ export interface ForkOpts {
260
+ count?: number;
261
+ /** Required when the sandbox is dirty (any exec/write): fork the origin snapshot. */
262
+ fromOrigin?: boolean;
263
+ onReady?: (sandbox: unknown, index: number) => void;
264
+ waitTimeoutMs?: number;
265
+ }
266
+ export interface SandboxOpts {
267
+ apiKey?: string;
268
+ apiUrl?: string;
269
+ /** `opts.spendCap` > `PROMIGENCE_SPEND_CAP` > `GET /me.default_spend_cap`; none → InvalidArgumentError. */
270
+ spendCap?: number;
271
+ /** Sandbox timeout: the most one sandbox can bill (per second used). */
272
+ timeoutMs?: number;
273
+ /** `false` → `network: none`. */
274
+ allowInternetAccess?: boolean;
275
+ /** Mapped to run labels. */
276
+ metadata?: Record<string, string>;
277
+ /**
278
+ * Plain environment variables for every command this object runs. Kept by this handle, not in
279
+ * the sandbox: a `Sandbox.connect(id)` elsewhere does not have them (pass them to its
280
+ * `connect`, or per command). A credential belongs in `secrets`, which every command gets.
281
+ */
282
+ envs?: Record<string, string>;
283
+ /** Bound on readiness (default 100 s). */
284
+ waitTimeoutMs?: number;
285
+ }
@@ -0,0 +1,266 @@
1
+ import { hintArg } from "./hint.js";
2
+ export const VERSION = "0.1.0-beta.12";
3
+ export const DOCS_URL = "https://promigence.ai";
4
+ export const ERRORS_DOCS_URL = "https://www.promigence.ai/docs/errors";
5
+ export const DEFAULT_API_URL = "https://api.promigence.ai/v1";
6
+ export const KEY_CONTACT = "support@promigence.ai";
7
+ export const WAIT_TIMEOUT_MS = 100_000;
8
+ export const IMAGE_BUILD_TIMEOUT_MS = 15 * 60_000;
9
+ export const IMAGE_BUILD_LIST_PRICE = 0.1656;
10
+ export const MAX_OUTPUT_BYTES_DEFAULT = 64 * 1024;
11
+ export const FILE_PUT_CHUNK_BYTES = 16 * 1024 * 1024;
12
+ const PREVIEWS_OFF = /^previews are not enabled on this deployment\.?$/i;
13
+ export const PREVIEWS_UNAVAILABLE = "preview URLs are not available in this beta yet";
14
+ export function previewsFix(sandboxId = "SID", port = 8000) {
15
+ return `Reach the port over SSH instead: \`promigence sandbox ssh ${hintArg(sandboxId)} -- -N -L ${hintArg(`${port}:localhost:${port}`)}\` ` +
16
+ `forwards http://localhost:${port} here to port ${port} in the sandbox until Ctrl-C.`;
17
+ }
18
+ export async function withPreviewsFix(call, sandboxId, port = "PORT") {
19
+ try {
20
+ return await call;
21
+ }
22
+ catch (e) {
23
+ if (e instanceof PromigenceError && e.message === PREVIEWS_UNAVAILABLE) {
24
+ Object.defineProperty(e, "fix", { value: previewsFix(sandboxId, port), enumerable: true, configurable: true });
25
+ }
26
+ throw e;
27
+ }
28
+ }
29
+ export function fixBeyondMessage(message, fix) {
30
+ const said = message.trim().replace(/[.\s]+$/, "");
31
+ if (said === "" || !fix.startsWith(said))
32
+ return fix;
33
+ const rest = fix.slice(said.length).replace(/^[.:;,\s]+/, "");
34
+ return rest === "" ? "Change what the message names, then try again." : rest;
35
+ }
36
+ export class PromigenceError extends Error {
37
+ code;
38
+ fix;
39
+ docs;
40
+ exitCode;
41
+ cliExit;
42
+ guide;
43
+ status;
44
+ requestId;
45
+ retryAfterMs;
46
+ category;
47
+ retryable;
48
+ constructor(init) {
49
+ const previewsOff = PREVIEWS_OFF.test(init.message.trim());
50
+ const code = previewsOff && init.code === "usage" ? "unsupported" : init.code;
51
+ super(previewsOff ? PREVIEWS_UNAVAILABLE : init.message);
52
+ this.name = new.target.name;
53
+ this.code = code;
54
+ this.fix = previewsOff ? previewsFix() : fixBeyondMessage(init.message, init.fix);
55
+ this.docs = init.docs ?? DOCS_URL;
56
+ this.exitCode = init.exitCode ?? 1;
57
+ this.cliExit = init.exitCode ?? 1;
58
+ this.guide = `promigence agent-guide --section errors --code ${hintArg(code)}`;
59
+ this.status = init.status;
60
+ this.requestId = init.requestId;
61
+ this.retryAfterMs = init.retryAfterMs;
62
+ this.category = init.category;
63
+ this.retryable = init.retryable;
64
+ }
65
+ toJSON() {
66
+ return {
67
+ code: this.code, message: this.message, fix: this.fix, docs: this.docs, guide: this.guide,
68
+ ...(this.requestId === undefined ? {} : { request_id: this.requestId }),
69
+ ...(this.category === undefined ? {} : { category: this.category }),
70
+ ...(this.retryable === undefined ? {} : { retryable: this.retryable }),
71
+ };
72
+ }
73
+ }
74
+ export class InvalidArgumentError extends PromigenceError {
75
+ constructor(message, fix, code = "invalid_argument") {
76
+ super({ code, message, fix, exitCode: 2 });
77
+ }
78
+ }
79
+ export class UnsupportedError extends PromigenceError {
80
+ constructor(feature, alternative) {
81
+ super({
82
+ code: "unsupported",
83
+ message: `${feature} is not supported by Promigence v0.`,
84
+ fix: alternative,
85
+ exitCode: 2,
86
+ });
87
+ }
88
+ static [Symbol.hasInstance](x) {
89
+ if (Function.prototype[Symbol.hasInstance].call(this, x))
90
+ return true;
91
+ return this === UnsupportedError && x instanceof PreviewsUnavailableError;
92
+ }
93
+ }
94
+ export function previewsOff(message) {
95
+ return PREVIEWS_OFF.test(message.trim());
96
+ }
97
+ export class PreviewsUnavailableError extends InvalidArgumentError {
98
+ constructor(sandboxId = "SID", port = 8000) {
99
+ super(PREVIEWS_UNAVAILABLE, previewsFix(sandboxId, port), "unsupported");
100
+ }
101
+ }
102
+ export class EnvFailedError extends PromigenceError {
103
+ constructor(code, message, fix) {
104
+ super({ code, message, fix, exitCode: 3 });
105
+ }
106
+ }
107
+ export class CommandExitError extends PromigenceError {
108
+ exitCodeOfCommand;
109
+ stdout;
110
+ stderr;
111
+ exitCode;
112
+ constructor(result) {
113
+ super({
114
+ code: "task_failed",
115
+ message: `command exited with code ${result.exitCode}`,
116
+ fix: "Inspect result.stdout / result.stderr; pass { throwOnExit: false } to receive the result instead.",
117
+ exitCode: 4,
118
+ });
119
+ this.exitCode = result.exitCode;
120
+ this.exitCodeOfCommand = result.exitCode;
121
+ this.stdout = result.stdout;
122
+ this.stderr = result.stderr;
123
+ }
124
+ }
125
+ export class SpendCapError extends PromigenceError {
126
+ constructor(message, fix, code = "cap_exceeded") {
127
+ super({
128
+ code,
129
+ message,
130
+ fix: fix ?? "Raise --cap / spendCap, lower count or timeout, or pass allowPartial to launch what fits.",
131
+ exitCode: exitForCode(code),
132
+ });
133
+ }
134
+ }
135
+ export class NotVerifiedError extends PromigenceError {
136
+ constructor(message, fix) {
137
+ super({
138
+ code: "not_verified",
139
+ message,
140
+ fix: fix ?? "Wait for the build: `promigence snapshot status <build_id> --wait`.",
141
+ exitCode: 6,
142
+ });
143
+ }
144
+ }
145
+ export class AuthError extends PromigenceError {
146
+ constructor(message = "missing or invalid API key", fix) {
147
+ super({
148
+ code: "auth",
149
+ message,
150
+ fix: fix ??
151
+ "No key yet: `promigence login` signs you up or in and stores one. A key you already " +
152
+ "have: set PROMIGENCE_API_KEY, or store it with `promigence auth login --from-env VAR`.",
153
+ exitCode: 7,
154
+ });
155
+ }
156
+ }
157
+ export class NotFoundError extends PromigenceError {
158
+ constructor(message, fix) {
159
+ super({
160
+ code: "not_found",
161
+ message,
162
+ fix: fix ?? "Check the id; aliases resolve in your org first, then public snapshots (`promigence examples`).",
163
+ exitCode: 8,
164
+ });
165
+ }
166
+ }
167
+ export class UnreachableError extends PromigenceError {
168
+ constructor(message, fix) {
169
+ super({
170
+ code: "unreachable",
171
+ message,
172
+ fix: fix ?? `Check PROMIGENCE_API_URL and connectivity; the API is at ${DEFAULT_API_URL}.`,
173
+ exitCode: 9,
174
+ });
175
+ }
176
+ }
177
+ export class RateLimitError extends PromigenceError {
178
+ constructor(message, retryAfterMs) {
179
+ super({
180
+ code: "rate_limited",
181
+ message,
182
+ fix: retryAfterMs ? `Retry after ${retryAfterMs} ms.` : "Retry with backoff; reduce concurrency (see `GET /me` limits).",
183
+ exitCode: 10,
184
+ ...(retryAfterMs === undefined ? {} : { retryAfterMs }),
185
+ });
186
+ }
187
+ }
188
+ export class TimeoutError extends PromigenceError {
189
+ sandboxId;
190
+ runId;
191
+ constructor(message, fix, ids = {}) {
192
+ super({ code: "timeout", message, fix, exitCode: 11 });
193
+ this.sandboxId = ids.sandboxId;
194
+ this.runId = ids.runId;
195
+ }
196
+ }
197
+ export class ServiceRestartError extends PromigenceError {
198
+ constructor(message, fix) {
199
+ super({ code: "service_restart", message, fix, exitCode: 3, category: "env", retryable: false });
200
+ }
201
+ }
202
+ export class ApiError extends PromigenceError {
203
+ }
204
+ export class NotReleasedError extends PromigenceError {
205
+ constructor(what) {
206
+ super({
207
+ code: "not_released",
208
+ message: `${what} is not released yet: promigence@${VERSION} does not implement it. The runtime ships from Oct 2026.`,
209
+ fix: `Update from the package you were given once a release implements it (support@promigence.ai has the latest); until then see ${DOCS_URL}.`,
210
+ exitCode: 1,
211
+ });
212
+ }
213
+ }
214
+ export const EXIT_BY_CODE = {
215
+ invalid_argument: 2, unsupported: 2, not_released: 1, task_failed: 4,
216
+ env_failed: 3, snapshot_rejected: 6, build_failed: 3, snapshot_failed: 4,
217
+ not_connected: 7,
218
+ service_restart: 3,
219
+ fork_failed: 3, start_timeout: 3, readiness_failed: 3, verify_too_slow: 3,
220
+ verify_each_failed: 3, toolchain_mismatch: 3, sandbox_unresponsive: 3, oom_within_tier: 3,
221
+ disk_full_within_tier: 3, sandbox_interrupted: 3, integrity_mismatch: 3, egress_unavailable: 3,
222
+ service_timeout: 3, capacity_busy: 3, region_at_capacity: 3,
223
+ preempted: 3,
224
+ tier_unavailable: 3,
225
+ snapshot_unavailable: 3,
226
+ capacity_limit: 3,
227
+ builder_unavailable: 3,
228
+ builder_busy: 3,
229
+ overloaded: 3,
230
+ verify_did_not_cover: 4,
231
+ grader_failed: 3,
232
+ nonzero_exit: 4, grade_not_passed: 4, task_timeout: 4, oom_over_tier: 4, disk_over_tier: 4,
233
+ shutdown_by_task: 4, modified_by_task: 4,
234
+ cap_exceeded: 5, cap_killed: 12, cap_paused: 5, credits_paused: 5,
235
+ aborted_by_client: 130, stopped_by_support: 12, expired: 12, not_started: 12, superseded: 0,
236
+ usage: 2, internal: 1, auth: 7, not_found: 8, unreachable: 9, rate_limited: 10,
237
+ timeout: 11, not_verified: 6, enoent: 8,
238
+ snapshot_incompatible: 6, storage_limit_reached: 5,
239
+ resume_unavailable: 3,
240
+ sandbox_unreachable: 3,
241
+ dockerfile_build_failed: 2,
242
+ build_timeout: 4,
243
+ image_unresolvable: 2,
244
+ registry_unavailable: 3,
245
+ trial_credits_exhausted: 5, card_required: 5, credit_unclaimed: 5, concurrency_limit: 5, egress_cap_reached: 5,
246
+ billing_unavailable: 5,
247
+ project_cap_reached: 5,
248
+ spend_limit_reached: 5,
249
+ billing_hold: 5,
250
+ tier_over_plan: 2,
251
+ network_host_refused: 9, network_policy_unsupported: 3,
252
+ secrets_in_snapshot: 2, secrets_unavailable: 3,
253
+ secret_binding_unsupported: 3,
254
+ idempotency_key_reused: 2, idempotency_key_in_use: 3,
255
+ repo_credentials_not_supported: 2,
256
+ forbidden: 7,
257
+ account_exists: 7,
258
+ invite_invalid: 7,
259
+ invite_required: 7,
260
+ key_expired: 7,
261
+ account_blocked: 7,
262
+ setup_required: 7,
263
+ };
264
+ export function exitForCode(code) {
265
+ return Object.prototype.hasOwnProperty.call(EXIT_BY_CODE, code) ? EXIT_BY_CODE[code] : 1;
266
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Where a stored sign-in lives: the operating system's keychain when this machine has one, else
3
+ * the credentials file (`~/.config/promigence/credentials`, 0600). The CLI writes it
4
+ * (`promigence login`, `promigence auth login`, `promigence logout`); the CLI and both SDKs read it.
5
+ *
6
+ * macOS the login Keychain, through `security` (when the user's home holds one: HOME,
7
+ * or the account's own home when the environment has no HOME)
8
+ * Linux and BSD the Secret Service (GNOME Keyring, KWallet), through `secret-tool`, when a
9
+ * desktop session bus is there (a CI job or an SSH shell has none: the file)
10
+ * Windows the file: no tool that ships with Windows can read a stored secret back
11
+ * without a native module or a compiled helper on every command
12
+ *
13
+ * `PROMIGENCE_CREDENTIAL_STORE=file` keeps the file on any machine; `macos-keychain` and
14
+ * `secret-service` name a keychain outright (`auto`, the default, picks by platform).
15
+ *
16
+ * One keychain item per credentials path (service `promigence-cli`, account = the path), so two
17
+ * `XDG_CONFIG_HOME` directories are two sign-ins, exactly as two files were. The item holds the
18
+ * same JSON the file did. The secret never goes on a command line, where `ps` would show it:
19
+ * `security` takes the whole command on stdin (`security -i`) with the data hex-encoded, and
20
+ * `secret-tool store` reads the secret from stdin.
21
+ *
22
+ * A file that is present wins over the keychain: the CLI deletes the file once the keychain holds
23
+ * the same sign-in and reads it back, so a file that is there was written after (by hand, by an
24
+ * older CLI, or because the keychain was not usable at the time).
25
+ */
26
+ /** Where a stored sign-in lives. */
27
+ export type CredentialStore = "file" | "macos-keychain" | "secret-service";
28
+ /** An OS keychain: the stores that are not the file. */
29
+ export type KeychainStore = Exclude<CredentialStore, "file">;
30
+ /** The keychain item's service name. The account is the credentials path. */
31
+ export declare const KEYCHAIN_SERVICE = "promigence-cli";
32
+ /** How each store is named in a message. */
33
+ export declare function storeLabel(store: CredentialStore, path?: string): string;
34
+ /**
35
+ * The keychain this process stores a sign-in in, or undefined for the file. `auto` is decided by
36
+ * the platform and by whether its tool (and, for the Secret Service, a session bus) is there.
37
+ */
38
+ export declare function keychainStore(env?: NodeJS.ProcessEnv, platform?: string, home?: () => string): KeychainStore | undefined;
39
+ /**
40
+ * The keychains a sign-out (or a sign-in that lands in the file) must clear for this path: the one
41
+ * in use, and the platform's own even when `PROMIGENCE_CREDENTIAL_STORE=file` (an item a previous
42
+ * sign-in left there would otherwise still sign commands in once the file is gone).
43
+ */
44
+ export declare function keychainsToClear(env?: NodeJS.ProcessEnv, platform?: string): KeychainStore[];
45
+ /** A keychain that holds (or may hold) the sign-in but could not be read. */
46
+ export interface KeychainUnavailable {
47
+ store: KeychainStore;
48
+ reason: string;
49
+ locked: boolean;
50
+ }
51
+ /** What a keychain read found. */
52
+ export type KeychainRead = {
53
+ status: "found";
54
+ text: string;
55
+ } | {
56
+ status: "absent";
57
+ } | {
58
+ status: "unavailable";
59
+ reason: string;
60
+ locked: boolean;
61
+ };
62
+ /** The item for `account` in `store`, read now (no cache). */
63
+ export declare function keychainRead(store: KeychainStore, account: string, env?: NodeJS.ProcessEnv): KeychainRead;
64
+ /** Store `text` as the item for `account`. Never puts `text` on a command line. */
65
+ export declare function keychainWrite(store: KeychainStore, account: string, text: string, env?: NodeJS.ProcessEnv): {
66
+ ok: true;
67
+ } | {
68
+ ok: false;
69
+ reason: string;
70
+ };
71
+ /** Remove the item for `account`. `absent` when there was none. */
72
+ export declare function keychainDelete(store: KeychainStore, account: string, env?: NodeJS.ProcessEnv): {
73
+ ok: true;
74
+ absent: boolean;
75
+ } | {
76
+ ok: false;
77
+ reason: string;
78
+ locked: boolean;
79
+ };
80
+ /**
81
+ * The JSON a store holds, in printable ASCII only (`security -w` prints anything else as hex). The
82
+ * same object the credentials file holds.
83
+ */
84
+ export declare function encodeCredentials(body: Record<string, string>): string;
85
+ /** `keychainRead`, remembered for a few seconds per store and account. */
86
+ export declare function keychainReadCached(store: KeychainStore, account: string, env?: NodeJS.ProcessEnv): KeychainRead;
87
+ /** Record what a store now holds for `account` (undefined = nothing), after this process wrote it. */
88
+ export declare function keychainCacheSet(store: KeychainStore, account: string, text: string | undefined): void;
89
+ /** Forget every remembered read, so the next one asks the keychain (a long-lived process, the MCP server). */
90
+ export declare function forgetKeychainReads(): void;