promigence 0.1.0-beta.6 → 0.1.0-beta.8
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.
- package/README.md +4 -6
- package/dist/account.js +107 -1
- package/dist/agent.js +11 -1
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +20 -15
- package/dist/credits.js +10 -7
- package/dist/devcontainer.d.ts +5 -0
- package/dist/devcontainer.js +5 -0
- package/dist/dirsnap.js +1 -1
- package/dist/errfix.js +1 -0
- package/dist/generated.js +18 -3
- package/dist/github.js +2 -3
- package/dist/gitlab.js +2 -2
- package/dist/guide.js +40 -10
- package/dist/handlers.js +2 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/live.js +8 -0
- package/dist/login.js +3 -1
- package/dist/mcp.js +3 -0
- package/dist/pricing.d.ts +3 -1
- package/dist/pricing.js +10 -7
- package/dist/routes.js +1 -0
- package/dist/runners-spec.js +22 -11
- package/dist/runners.js +2 -2
- package/dist/sdk/client.d.ts +100 -24
- package/dist/sdk/client.js +46 -33
- package/dist/sdk/core.d.ts +10 -1
- package/dist/sdk/core.js +12 -3
- package/dist/sdk/credstore.d.ts +3 -2
- package/dist/sdk/credstore.js +17 -4
- package/dist/sdk/models.gen.d.ts +218 -22
- package/dist/sdk/proxy.js +2 -1
- package/dist/sdk/pty.d.ts +65 -3
- package/dist/sdk/pty.js +269 -33
- package/dist/sdk/sandbox.d.ts +34 -4
- package/dist/sdk/sandbox.js +3 -2
- package/dist/sdk/ssh.js +1 -0
- package/dist/surface.d.ts +4 -3
- package/dist/surface.js +25 -13
- package/llms.txt +21 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,15 +21,13 @@ own (`npm config set prefix ~/.npm-global` and add `~/.npm-global/bin` to your `
|
|
|
21
21
|
|
|
22
22
|
## Create your account
|
|
23
23
|
|
|
24
|
-
Promigence is in private beta: you need an invite code.
|
|
25
|
-
|
|
26
24
|
```sh
|
|
27
25
|
promigence signup
|
|
28
26
|
```
|
|
29
27
|
|
|
30
|
-
It
|
|
31
|
-
|
|
32
|
-
another machine, use `promigence login`: it signs you in with a code we email you
|
|
28
|
+
It opens your browser to create the account. Your API key is saved in your system keychain, or in
|
|
29
|
+
`~/.config/promigence/credentials` (mode 0600) where there is none.
|
|
30
|
+
On another machine, use `promigence login`: it signs you in with a code we email you. In CI or on an
|
|
33
31
|
agent's machine, set `PROMIGENCE_API_KEY` instead. `promigence doctor` checks the setup.
|
|
34
32
|
|
|
35
33
|
## First commands
|
|
@@ -57,7 +55,7 @@ promigence fork --snapshot py --count 5 --cap 2
|
|
|
57
55
|
|
|
58
56
|
## For AI agents
|
|
59
57
|
|
|
60
|
-
Run `promigence agent-guide` (about 1.
|
|
58
|
+
Run `promigence agent-guide` (about 1.4k tokens) before driving the CLI: it covers the model, the
|
|
61
59
|
JSON output contract, exit codes and errors. `promigence agent-guide --install` writes the same
|
|
62
60
|
guidance into your repo for coding agents, and `promigence mcp` serves the CLI as an MCP server.
|
|
63
61
|
Every command takes `--json`.
|
package/dist/account.js
CHANGED
|
@@ -4,6 +4,21 @@ import { duration } from "./report.js";
|
|
|
4
4
|
import { emit, ms, okEnvelope, overMost, parseCount, parseDuration, parseUsd, usageError } from "./io.js";
|
|
5
5
|
import { sh } from "./term.js";
|
|
6
6
|
const usd = (n) => n === undefined ? "—" : `$${n.toFixed(n < 0.01 && n > 0 ? 4 : 2)}`;
|
|
7
|
+
export const PAYMENT_METHOD_NAMES = {
|
|
8
|
+
apple_pay: "Apple Pay",
|
|
9
|
+
google_pay: "Google Pay",
|
|
10
|
+
samsung_pay: "Samsung Pay",
|
|
11
|
+
link: "Link",
|
|
12
|
+
cashapp: "Cash App Pay",
|
|
13
|
+
amazon_pay: "Amazon Pay",
|
|
14
|
+
};
|
|
15
|
+
export function paymentMethodText(card) {
|
|
16
|
+
const key = card?.brand ?? "";
|
|
17
|
+
const named = Object.prototype.hasOwnProperty.call(PAYMENT_METHOD_NAMES, key) ? PAYMENT_METHOD_NAMES[key] : undefined;
|
|
18
|
+
if (named)
|
|
19
|
+
return card?.last4 ? `${named} •••• ${card.last4}` : named;
|
|
20
|
+
return `${card?.brand ?? "card"} ••${card?.last4 ?? "??"}`;
|
|
21
|
+
}
|
|
7
22
|
function limitOf(ctx, fallback, most) {
|
|
8
23
|
const raw = str(ctx, "--limit");
|
|
9
24
|
if (raw === undefined)
|
|
@@ -208,6 +223,7 @@ const billingUsage = async (ctx) => {
|
|
|
208
223
|
usage,
|
|
209
224
|
card_on_file: b.card_on_file ?? false,
|
|
210
225
|
...(b.card ? { card: b.card } : {}),
|
|
226
|
+
...(b.card_note ? { card_note: b.card_note } : {}),
|
|
211
227
|
...(b.trial ? { trial: b.trial } : {}),
|
|
212
228
|
...(b.suspended ? { suspended: true, suspend_reason: b.suspend_reason ?? null } : {}),
|
|
213
229
|
upcoming_invoice: b.upcoming_invoice ?? null,
|
|
@@ -244,7 +260,9 @@ const billingUsage = async (ctx) => {
|
|
|
244
260
|
const trial = b.trial;
|
|
245
261
|
if (trial?.credits_remaining !== undefined)
|
|
246
262
|
lines.push(` trial credits left: ${usd(trial.credits_remaining)}`);
|
|
247
|
-
lines.push(` card: ${b.card_on_file ?
|
|
263
|
+
lines.push(` card: ${b.card_on_file ? paymentMethodText(b.card) : `none on file${billingOff ? " (card payments are not open yet)" : ""}`}`);
|
|
264
|
+
if (b.card_note)
|
|
265
|
+
lines.push(` ${b.card_note}`);
|
|
248
266
|
if (b.upcoming_invoice?.amount_due !== undefined && b.upcoming_invoice?.amount_due !== null) {
|
|
249
267
|
lines.push(` next invoice: ${usd(b.upcoming_invoice.amount_due)}`);
|
|
250
268
|
}
|
|
@@ -267,6 +285,86 @@ const billingPortal = async (ctx) => {
|
|
|
267
285
|
const next = nexts(["promigence billing usage", "this month's spend without leaving the terminal"]);
|
|
268
286
|
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { url: res.url }, next), ["promigence billing portal: open this page to manage the card and past invoices:", ` ${res.url}`], 0, ctx.pointer);
|
|
269
287
|
};
|
|
288
|
+
const HISTORY_KINDS = ["all", "credits", "payments"];
|
|
289
|
+
const CREDIT_WHAT = {
|
|
290
|
+
free_credit: "Free credit",
|
|
291
|
+
card_bonus: "Card bonus",
|
|
292
|
+
referral: "Referral reward",
|
|
293
|
+
plan: "Included with your plan",
|
|
294
|
+
from_promigence: "Credit from Promigence",
|
|
295
|
+
service_restart: "Credit for a service restart",
|
|
296
|
+
confirmation_credit: "Credit for the $1 confirmation",
|
|
297
|
+
};
|
|
298
|
+
const CREDIT_ENDED = { used: "used", expired: "expired", taken_back: "taken back" };
|
|
299
|
+
const PAYMENT_WHAT = {
|
|
300
|
+
invoice_paid: "Invoice paid",
|
|
301
|
+
payment_failed: "Payment failed",
|
|
302
|
+
refund: "Refund",
|
|
303
|
+
};
|
|
304
|
+
const PAYMENT_STATUS = {
|
|
305
|
+
paid: "paid",
|
|
306
|
+
retrying: "will be retried",
|
|
307
|
+
failed: "not paid",
|
|
308
|
+
refunded: "refunded",
|
|
309
|
+
confirmed: "confirmed",
|
|
310
|
+
};
|
|
311
|
+
const wordFor = (m, k) => k && Object.prototype.hasOwnProperty.call(m, k) ? m[k] : undefined;
|
|
312
|
+
const unpaid = (status) => status === "retrying" || status === "failed";
|
|
313
|
+
export function historyLines(entries) {
|
|
314
|
+
return entries.map((e) => {
|
|
315
|
+
const day = (e.at ?? "").slice(0, 10);
|
|
316
|
+
const c = e.credit;
|
|
317
|
+
if (c) {
|
|
318
|
+
const state = wordFor(CREDIT_ENDED, c.status) ??
|
|
319
|
+
`${usd(c.remaining_usd)} left, ${c.expires_at ? `expires ${c.expires_at.slice(0, 10)}` : "no expiry"}`;
|
|
320
|
+
return ` ${day} ${wordFor(CREDIT_WHAT, c.kind) ?? "Credit"} ${usd(c.granted_usd)} ${state}`;
|
|
321
|
+
}
|
|
322
|
+
const p = e.payment;
|
|
323
|
+
if (!p)
|
|
324
|
+
return ` ${day} (a row this version cannot show: see --json)`;
|
|
325
|
+
const check = p.kind === "method_check";
|
|
326
|
+
const what = check
|
|
327
|
+
? `$${Number.isInteger(p.amount_usd) ? String(p.amount_usd) : p.amount_usd.toFixed(2)} to confirm ${p.method || "your payment method"}`
|
|
328
|
+
: (wordFor(PAYMENT_WHAT, p.kind) ?? "Payment");
|
|
329
|
+
const detail = [p.plan ? `${p.plan} plan` : null, p.invoice_number ? `invoice ${p.invoice_number}` : null]
|
|
330
|
+
.filter(Boolean)
|
|
331
|
+
.join(", ");
|
|
332
|
+
const status = check && p.status === "failed" ? "failed" : (wordFor(PAYMENT_STATUS, p.status) ?? p.status);
|
|
333
|
+
const url = typeof p.invoice_url === "string" && p.invoice_url.startsWith("https://") ? p.invoice_url : null;
|
|
334
|
+
const link = url && !check ? ` · ${unpaid(p.status) ? "pay at" : "receipt"} ${url}` : "";
|
|
335
|
+
return ` ${day} ${what}${detail ? ` (${detail})` : ""} ${usd(p.amount_usd)} ${status}${link}`;
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
const billingHistory = async (ctx) => {
|
|
339
|
+
const kind = str(ctx, "--kind") ?? "all";
|
|
340
|
+
if (!HISTORY_KINDS.includes(kind)) {
|
|
341
|
+
throw usageError(`--kind: '${kind}' is not a kind`, `Pass one of ${HISTORY_KINDS.join(" | ")}.`);
|
|
342
|
+
}
|
|
343
|
+
const limit = limitOf(ctx, 50, 100);
|
|
344
|
+
const cursor = str(ctx, "--cursor");
|
|
345
|
+
const page = await client(ctx).billing.historyPage({
|
|
346
|
+
kind: kind,
|
|
347
|
+
limit,
|
|
348
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
349
|
+
});
|
|
350
|
+
const entries = page.items;
|
|
351
|
+
const more = page.nextCursor;
|
|
352
|
+
const owed = entries.some((e) => e.payment && e.payment.kind !== "method_check" && unpaid(e.payment.status));
|
|
353
|
+
const next = nexts(...(more
|
|
354
|
+
? [[`${sh `promigence billing history --limit ${String(limit)}`}${kind === "all" ? "" : sh ` --kind ${kind}`}${sh ` --cursor ${more}`}`, "the next page"]]
|
|
355
|
+
: []), ...(owed
|
|
356
|
+
? [["promigence billing portal", "pay the open invoice, or update the card on file"]]
|
|
357
|
+
: [["promigence billing usage", "this month's spend and credit"]]));
|
|
358
|
+
const empty = { all: "no credits or payments yet", credits: "no credit yet", payments: "no payments yet" };
|
|
359
|
+
const noun = kind === "all" ? "" : ` ${entries.length === 1 ? kind.slice(0, -1) : kind}`;
|
|
360
|
+
const lines = [
|
|
361
|
+
`promigence billing history: ${entries.length}${noun}, newest first`,
|
|
362
|
+
...historyLines(entries),
|
|
363
|
+
...(entries.length ? [] : [` (${empty[kind]})`]),
|
|
364
|
+
...(more ? [` more: --cursor ${more}`] : []),
|
|
365
|
+
];
|
|
366
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { kind, entries, count: entries.length, next_cursor: more }, next), lines, 0, ctx.pointer);
|
|
367
|
+
};
|
|
270
368
|
const referrals = async (ctx) => {
|
|
271
369
|
const r = await client(ctx).billing.referrals();
|
|
272
370
|
const next = r.code
|
|
@@ -520,6 +618,12 @@ export function sandboxFactLines(s, facts, nowMs = Date.now()) {
|
|
|
520
618
|
}
|
|
521
619
|
return out;
|
|
522
620
|
}
|
|
621
|
+
export function supportStopLines(s) {
|
|
622
|
+
if (s.outcome !== "stopped_by_support")
|
|
623
|
+
return [];
|
|
624
|
+
const message = s.failure?.message;
|
|
625
|
+
return [` ${typeof message === "string" && message.trim() ? message : "Stopped by Promigence support"}`];
|
|
626
|
+
}
|
|
523
627
|
const sandboxInfo = async (ctx) => {
|
|
524
628
|
const sid = positional(ctx, "a sandbox id", "promigence sandbox info sbx_01");
|
|
525
629
|
const c = client(ctx);
|
|
@@ -539,6 +643,7 @@ const sandboxInfo = async (ctx) => {
|
|
|
539
643
|
: why ? [] : [[sh `promigence exec --sandbox ${sid} -- CMD`, "run something in it"]]));
|
|
540
644
|
const lines = [
|
|
541
645
|
`sandbox ${sid}: ${s.state}${why ? ` (${why})` : ""}${s.outcome ? ` (${s.outcome})` : ""}${s.run_id ? ` · run ${s.run_id}` : ""}`,
|
|
646
|
+
...supportStopLines(s),
|
|
542
647
|
...(why ? [" its files and state are kept, and paused time is not billed"] : []),
|
|
543
648
|
...queuedLines([s]),
|
|
544
649
|
...(s.snapshot_id ? [` snapshot ${s.snapshot_id}`] : []),
|
|
@@ -723,6 +828,7 @@ export const ACCOUNT_HANDLERS = {
|
|
|
723
828
|
status,
|
|
724
829
|
"billing usage": billingUsage,
|
|
725
830
|
"billing portal": billingPortal,
|
|
831
|
+
"billing history": billingHistory,
|
|
726
832
|
referrals,
|
|
727
833
|
"referrals apply": referralsApply,
|
|
728
834
|
"snapshot delete": snapshotDelete,
|
package/dist/agent.js
CHANGED
|
@@ -42,9 +42,17 @@ export const SETUP_SCRIPT = [
|
|
|
42
42
|
'if [ -n "$3" ] && [ ! -d "$4/.git" ]; then',
|
|
43
43
|
' mkdir -p "$(dirname "$4")"',
|
|
44
44
|
' git clone --quiet -- "$3" "$4" >&2',
|
|
45
|
+
' if [ -n "${5:-}" ]; then chown -R -- "$5" "$4"; fi',
|
|
45
46
|
"fi",
|
|
46
47
|
'"$1" --version',
|
|
47
48
|
].join("\n");
|
|
49
|
+
async function snapshotUser(c, snapshot) {
|
|
50
|
+
if (snapshot === DEFAULT_SNAPSHOT)
|
|
51
|
+
return undefined;
|
|
52
|
+
const rec = await c.snapshots.get(snapshot).catch(() => undefined);
|
|
53
|
+
const u = rec?.user;
|
|
54
|
+
return typeof u === "string" && u !== "" && u !== "root" && u !== "0" ? u : undefined;
|
|
55
|
+
}
|
|
48
56
|
export function repoDir(url) {
|
|
49
57
|
const last = url.replace(/[/]+$/, "").split(/[/:]/).pop() ?? "";
|
|
50
58
|
const name = last.replace(/\.git$/, "").replace(/[^A-Za-z0-9._-]/g, "") || "repo";
|
|
@@ -269,8 +277,10 @@ const agentStart = async (ctx) => {
|
|
|
269
277
|
throw e;
|
|
270
278
|
}
|
|
271
279
|
};
|
|
280
|
+
const runAs = await snapshotUser(c, snapshot);
|
|
272
281
|
const setup = await endOnThrow(c.sandboxes.exec(sid, {
|
|
273
|
-
argv: ["sh", "-c", SETUP_SCRIPT, "agent-setup", agent.bin, agent.pkg, repo ?? "", cwd ?? ""],
|
|
282
|
+
argv: ["sh", "-c", SETUP_SCRIPT, "agent-setup", agent.bin, agent.pkg, repo ?? "", cwd ?? "", runAs ?? ""],
|
|
283
|
+
user: "root",
|
|
274
284
|
timeoutMs: 10 * 60_000,
|
|
275
285
|
}));
|
|
276
286
|
if (setup.exit_code !== 0) {
|
package/dist/commands.d.ts
CHANGED
|
@@ -99,6 +99,10 @@ export declare function outputTails(c: PromigenceClient, sandboxes: ReadonlyArra
|
|
|
99
99
|
}>;
|
|
100
100
|
}>): Promise<Map<string, OutputTail>>;
|
|
101
101
|
export declare function positional(ctx: Ctx, what: string, example: string): string;
|
|
102
|
+
export declare function supportStoppedLines(sandboxes: ReadonlyArray<{
|
|
103
|
+
sandbox_id: string;
|
|
104
|
+
outcome?: string | null;
|
|
105
|
+
}>): string[];
|
|
102
106
|
export declare function filesPutTarArgs(out: string, parent: string, base: string, noMetadata?: string[]): string[];
|
|
103
107
|
export declare const HANDLERS: Readonly<Record<string, Handler>>;
|
|
104
108
|
export {};
|
package/dist/commands.js
CHANGED
|
@@ -6,7 +6,7 @@ import { basename, dirname, join, resolve } from "node:path";
|
|
|
6
6
|
import { DEFAULT_API_URL, DEFAULT_SNAPSHOT, ERRORS_DOCS_URL, MAX_OUTPUT_BYTES_DEFAULT, CONTEXT_GIT_RE, PromigenceClient, checkRepoUrl, withoutPin, PromigenceError, SpendCapError, TimeoutError, checkImageRef, contextRelative, credentialsPath, FILE_PUT_CHUNK_BYTES, imageSnapshot, isWaiting, execOutputBytes, listContext, packContext, readCredentials, } from "./sdk/index.js";
|
|
7
7
|
import { fmtMs, recordTiming } from "./timing.js";
|
|
8
8
|
import { capacityLine, queuedClause, queuedLines, statusLine } from "./capacity.js";
|
|
9
|
-
import { DevcontainerError, detectOne, load, planJson, planLines, planSetup, resolveGiven, snapshotEnv, translate, workspaceRootFor, wrapCommand, } from "./devcontainer.js";
|
|
9
|
+
import { DevcontainerError, detectOne, load, planJson, planLines, planSetup, resolveGiven, snapshotEnv, snapshotUsers, translate, workspaceRootFor, wrapCommand, } from "./devcontainer.js";
|
|
10
10
|
import { detect, ecosystemOfCommands, imageCreateCommand, readConfig } from "./init.js";
|
|
11
11
|
import { CREDENTIAL_REMEDY, confirmOverride, credentialRefusal, emitUploadList, localTarNoMetadataArgs } from "./uploadguard.js";
|
|
12
12
|
import { emit, errorEnvelope, errorTextLines, exitWith, forkLine, forkSummary, gradeLine, ms, noCommandFix, okEnvelope, parseMaxOutput, recordNotice, sandboxGrade, parseCommandTimeout, parseCount, parseDuration, parseUsd, pickExit, reportSummaryLines, toPromigenceError, totalsLine, usageError, write, writeBytes, } from "./io.js";
|
|
@@ -212,7 +212,7 @@ function reportExits(report) {
|
|
|
212
212
|
return codes;
|
|
213
213
|
if (t.env_failed > 0 || (t.grader_failed ?? 0) > 0)
|
|
214
214
|
codes.push(3);
|
|
215
|
-
if (t.not_started > 0 || t.cap_killed > 0 || t.expired > 0)
|
|
215
|
+
if (t.not_started > 0 || t.cap_killed > 0 || t.expired > 0 || (t.stopped_by_support ?? 0) > 0)
|
|
216
216
|
codes.push(12);
|
|
217
217
|
if (t.task_failed > 0 || t.snapshot_failed > 0)
|
|
218
218
|
codes.push(4);
|
|
@@ -385,7 +385,7 @@ function boundUseLines(res) {
|
|
|
385
385
|
" requests the sandbox sends to this address are authenticated with it:",
|
|
386
386
|
...urls.map((u) => ` ${urlLine(u, res.env)}`),
|
|
387
387
|
` a request sent straight to ${hosts.map((h) => `https://${h}`).join(" or ")} is not authenticated: send it to the address above`,
|
|
388
|
-
...(res.scan_responses ===
|
|
388
|
+
...(res.scan_responses === true ? [" the host's answers never show the value: an echo service shows asterisks instead"] : []),
|
|
389
389
|
];
|
|
390
390
|
return lines;
|
|
391
391
|
}
|
|
@@ -723,7 +723,10 @@ async function devcontainerCreate(ctx, plan) {
|
|
|
723
723
|
}
|
|
724
724
|
const setup = planSetup(plan, { repo, commit, userSetup: list(ctx, "--setup") });
|
|
725
725
|
const env = snapshotEnv(plan);
|
|
726
|
-
const
|
|
726
|
+
const users = snapshotUsers(plan);
|
|
727
|
+
const opts = {
|
|
728
|
+
...source, ...(setup.length ? { setup } : {}), ...(env ? { env } : {}), ...(users ?? {}),
|
|
729
|
+
};
|
|
727
730
|
const verify = str(ctx, "--verify");
|
|
728
731
|
if (verify !== undefined)
|
|
729
732
|
opts.verify = { cmd: wrapCommand(plan, verify) };
|
|
@@ -762,7 +765,6 @@ const snapshotCreate = async (ctx) => {
|
|
|
762
765
|
const plan = gh ? undefined : devcontainerPlan(ctx, form);
|
|
763
766
|
const setup = list(ctx, "--setup");
|
|
764
767
|
const alias = str(ctx, "--alias");
|
|
765
|
-
const cpuClass = str(ctx, "--cpu-class");
|
|
766
768
|
let opts;
|
|
767
769
|
let label;
|
|
768
770
|
let submitted;
|
|
@@ -833,8 +835,6 @@ const snapshotCreate = async (ctx) => {
|
|
|
833
835
|
const c = client(ctx);
|
|
834
836
|
if (alias !== undefined)
|
|
835
837
|
opts.alias = alias;
|
|
836
|
-
if (cpuClass !== undefined)
|
|
837
|
-
opts.cpuClass = cpuClass;
|
|
838
838
|
const grade = gradeOpts(ctx);
|
|
839
839
|
if (grade)
|
|
840
840
|
opts.grade = grade;
|
|
@@ -1472,8 +1472,6 @@ const exec = async (ctx) => {
|
|
|
1472
1472
|
stdout: res.stdout ?? "",
|
|
1473
1473
|
stderr: res.stderr ?? "",
|
|
1474
1474
|
truncated: res.truncated ?? false,
|
|
1475
|
-
...(res.stdout_ref === undefined ? {} : { stdout_ref: res.stdout_ref }),
|
|
1476
|
-
...(res.stderr_ref === undefined ? {} : { stderr_ref: res.stderr_ref }),
|
|
1477
1475
|
...(res.stdout_b64 === undefined ? {} : { stdout_b64: res.stdout_b64 }),
|
|
1478
1476
|
...(res.stderr_b64 === undefined ? {} : { stderr_b64: res.stderr_b64 }),
|
|
1479
1477
|
...(res["idempotent_replay"] === true ? { idempotent_replay: true } : {}),
|
|
@@ -1598,7 +1596,7 @@ async function runImageSnapshot(ctx, c) {
|
|
|
1598
1596
|
if (cap < price + (quoted ?? 0)) {
|
|
1599
1597
|
const existing = (quoted ?? 0) <= cap ? await existingImageSnapshot(c, image) : undefined;
|
|
1600
1598
|
throw new SpendCapError(`a new image's snapshot build costs ${moneyUsd(price)} on top of the run` +
|
|
1601
|
-
`${quoted === undefined ? "" : ` (about ${moneyUsd(quoted)})`}, over --cap ${moneyUsd(cap)}; nothing was built or started`, (existing === undefined ? "" : `This image already has snapshot ${existing}: run it under this cap with ${sh `promigence run --snapshot ${existing}`} instead of --image. Or `) +
|
|
1599
|
+
`${quoted === undefined ? "" : ` (about ${moneyUsd(quoted)})`}, over --cap ${moneyUsd(cap)}; nothing was built or started`, (existing === undefined ? "" : `This image already has snapshot ${existing}: run it under this cap with ${sh `promigence run --snapshot ${existing}`} instead of --image (any start command or settings it was made with come with it). Or `) +
|
|
1602
1600
|
`${existing === undefined ? "Pass" : "pass"} --cap ${needed.toFixed(2)} or more (a build is charged once, only when this image has no snapshot yet, and reused free after), ` +
|
|
1603
1601
|
`or build it first, ${sh `promigence snapshot create --image ${image} --wait`}, and run its snapshot with --snapshot.`);
|
|
1604
1602
|
}
|
|
@@ -1633,7 +1631,7 @@ async function existingImageSnapshot(c, image) {
|
|
|
1633
1631
|
for (let page = 0; page < 5; page++) {
|
|
1634
1632
|
const p = await c.snapshots.listPage({ limit: 100, ...(cursor === undefined ? {} : { cursor }) });
|
|
1635
1633
|
const hit = p.items.find((s) => s.source?.kind === "image" && typeof s.source.digest === "string" && digests.has(s.source.digest) &&
|
|
1636
|
-
s.source["from_sandbox"] === undefined && !s.unavailable && !(s.setup?.length) && !s.
|
|
1634
|
+
s.source["from_sandbox"] === undefined && !s.unavailable && !(s.setup?.length) && !s.verify?.cmd &&
|
|
1637
1635
|
(s.tier === undefined || s.tier === "small"));
|
|
1638
1636
|
if (hit)
|
|
1639
1637
|
return hit.snapshot_id;
|
|
@@ -1967,11 +1965,12 @@ function settledWhy(report, keep) {
|
|
|
1967
1965
|
return `${open.length} sandbox${open.length === 1 ? " has" : "es have"} not ended yet, so ${open.length === 1 ? "its" : "their"} last charge is still to land`;
|
|
1968
1966
|
}
|
|
1969
1967
|
const OUTCOME_EXIT = {
|
|
1970
|
-
env_failed: 3, grader_failed: 3, not_started: 12, cap_killed: 12, expired: 12,
|
|
1968
|
+
env_failed: 3, grader_failed: 3, not_started: 12, cap_killed: 12, expired: 12, stopped_by_support: 12,
|
|
1969
|
+
task_failed: 4, snapshot_failed: 4,
|
|
1971
1970
|
};
|
|
1972
1971
|
const OUTCOME_CODE = {
|
|
1973
1972
|
env_failed: "env_failed", grader_failed: "grader_failed", not_started: "not_started", cap_killed: "cap_killed",
|
|
1974
|
-
expired: "expired", task_failed: "nonzero_exit", snapshot_failed: "snapshot_failed",
|
|
1973
|
+
expired: "expired", stopped_by_support: "stopped_by_support", task_failed: "nonzero_exit", snapshot_failed: "snapshot_failed",
|
|
1975
1974
|
};
|
|
1976
1975
|
function failureFix(runId, s) {
|
|
1977
1976
|
const f = s.failure;
|
|
@@ -2005,7 +2004,7 @@ export function runHeadline(report, count) {
|
|
|
2005
2004
|
const t = (report.totals ?? {});
|
|
2006
2005
|
const others = Object.entries(t)
|
|
2007
2006
|
.filter(([k, v]) => !["completed", "env_verified", "evidence_missing"].includes(k) && typeof v === "number" && v > 0)
|
|
2008
|
-
.map(([k, v]) => `${v} ${k}`);
|
|
2007
|
+
.map(([k, v]) => `${v} ${k === "stopped_by_support" ? "stopped by Promigence support" : k}`);
|
|
2009
2008
|
const done = typeof t["completed"] === "number" ? t["completed"] : 0;
|
|
2010
2009
|
return `run ${report.run_id}: ${done} of ${count} completed${others.length ? ` · ${others.join(" · ")}` : ""}` +
|
|
2011
2010
|
`${report.cost ? ` · charged ${moneyUsd(report.cost.charged)}` : ""}`;
|
|
@@ -2125,6 +2124,12 @@ const runReport = async (ctx) => {
|
|
|
2125
2124
|
const next = nexts([sh `promigence run status ${runId}`, "the run's current state"]);
|
|
2126
2125
|
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { run_id: runId, report }, next), reportLines(report, view), 0, ctx.pointer);
|
|
2127
2126
|
};
|
|
2127
|
+
export function supportStoppedLines(sandboxes) {
|
|
2128
|
+
const stopped = sandboxes.filter((s) => s.outcome === "stopped_by_support");
|
|
2129
|
+
if (!stopped.length)
|
|
2130
|
+
return [];
|
|
2131
|
+
return [` ${stopped.length} stopped by Promigence support; ${sh `promigence sandbox info ${stopped[0].sandbox_id}`} says why`];
|
|
2132
|
+
}
|
|
2128
2133
|
const runStatus = async (ctx) => {
|
|
2129
2134
|
const runId = positional(ctx, "a run id", "promigence run status run_01 --wait");
|
|
2130
2135
|
const c = client(ctx);
|
|
@@ -2141,7 +2146,7 @@ const runStatus = async (ctx) => {
|
|
|
2141
2146
|
states[s.state] = (states[s.state] ?? 0) + 1;
|
|
2142
2147
|
const next = nexts([sh `promigence run report ${runId} --json`, "the validity report"]);
|
|
2143
2148
|
const tail = Object.keys(states).length ? ` - ${Object.entries(states).map(([k, v]) => `${k} ${v}`).join(" - ")}` : "";
|
|
2144
|
-
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { run_id: runId, state: run.state, sandbox_states: states, run }, next), [`run ${runId}: ${run.state}${tail}`, ...queuedLines(run.sandboxes ?? [])], 0, ctx.pointer);
|
|
2149
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { run_id: runId, state: run.state, sandbox_states: states, run }, next), [`run ${runId}: ${run.state}${tail}`, ...supportStoppedLines(run.sandboxes ?? []), ...queuedLines(run.sandboxes ?? [])], 0, ctx.pointer);
|
|
2145
2150
|
};
|
|
2146
2151
|
const runKill = async (ctx) => {
|
|
2147
2152
|
const runId = positional(ctx, "a run id", "promigence run kill run_01");
|
package/dist/credits.js
CHANGED
|
@@ -150,18 +150,21 @@ export async function claimOnRefusal(ctx, io = {}) {
|
|
|
150
150
|
const opened = maybeOpen(ctx, link.url);
|
|
151
151
|
return [...claimLines(o, link, opened), "Once it is claimed, run the command again."];
|
|
152
152
|
}
|
|
153
|
-
async function
|
|
153
|
+
async function cardState(c, o) {
|
|
154
|
+
const none = { off: false, onFile: false };
|
|
154
155
|
if (!(typeof o.card_bonus_usd === "number" && o.card_bonus_usd > 0) || o.state === "none")
|
|
155
|
-
return
|
|
156
|
-
return c.billing.usage().then((b) => b.billing_enabled === false).catch(() =>
|
|
156
|
+
return none;
|
|
157
|
+
return c.billing.usage().then((b) => ({ off: b.billing_enabled === false, onFile: b.card_on_file === true })).catch(() => none);
|
|
157
158
|
}
|
|
158
|
-
function offerLines(head, o,
|
|
159
|
+
function offerLines(head, o, st = { off: false, onFile: false }) {
|
|
159
160
|
const lines = [`${head}: ${say(o)}`];
|
|
160
161
|
if (o.state !== "none") {
|
|
161
162
|
if (typeof o.credit_usd === "number")
|
|
162
163
|
lines.push(` credit: ${dollars(o.credit_usd)}`);
|
|
163
164
|
if (typeof o.card_bonus_usd === "number" && o.card_bonus_usd > 0) {
|
|
164
|
-
lines.push(
|
|
165
|
+
lines.push(st.onFile
|
|
166
|
+
? ` card bonus: ${dollars(o.card_bonus_usd)} more with your first paid invoice`
|
|
167
|
+
: ` card bonus: ${dollars(o.card_bonus_usd)} more when you add a card${st.off ? " (card payments are not open yet)" : " (promigence billing card)"}`);
|
|
165
168
|
}
|
|
166
169
|
if (o.expires_at)
|
|
167
170
|
lines.push(` expires: ${o.expires_at}`);
|
|
@@ -174,14 +177,14 @@ function offerLines(head, o, off = false) {
|
|
|
174
177
|
const credits = async (ctx) => {
|
|
175
178
|
const c = new PromigenceClient({ ...clientOpts(ctx), onNotice: recordNotice });
|
|
176
179
|
const o = await getOffer(c);
|
|
177
|
-
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...o }, offerNext(o)), offerLines("promigence credits", o, await
|
|
180
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...o }, offerNext(o)), offerLines("promigence credits", o, await cardState(c, o)), 0, ctx.pointer);
|
|
178
181
|
};
|
|
179
182
|
const creditsClaim = async (ctx) => {
|
|
180
183
|
const opts = { ...clientOpts(ctx), onNotice: recordNotice };
|
|
181
184
|
const c = new PromigenceClient(opts);
|
|
182
185
|
const o = await getOffer(c);
|
|
183
186
|
if (o.state !== "claimable") {
|
|
184
|
-
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...o, claim_url: null }, offerNext(o)), offerLines("promigence credits claim", o, await
|
|
187
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...o, claim_url: null }, offerNext(o)), offerLines("promigence credits claim", o, await cardState(c, o)), 0, ctx.pointer);
|
|
185
188
|
}
|
|
186
189
|
const link = await getClaimLink(claimClient(opts));
|
|
187
190
|
const opened = maybeOpen(ctx, link.url);
|
package/dist/devcontainer.d.ts
CHANGED
|
@@ -62,6 +62,7 @@ export interface Plan {
|
|
|
62
62
|
env: Record<string, string>;
|
|
63
63
|
workspaceFolder: string;
|
|
64
64
|
user: string | undefined;
|
|
65
|
+
remoteUser?: string | undefined;
|
|
65
66
|
lifecycle: LifecycleStep[];
|
|
66
67
|
ports: number[];
|
|
67
68
|
tier: string | undefined;
|
|
@@ -84,6 +85,10 @@ export declare function lifecycleSteps(v: unknown, field: string, ctx: Substitut
|
|
|
84
85
|
export declare function shellQuote(s: string): string;
|
|
85
86
|
export declare function wrapCommand(plan: Plan, command: string): string;
|
|
86
87
|
export declare function snapshotEnv(plan: Plan): Record<string, string> | undefined;
|
|
88
|
+
export declare function snapshotUsers(plan: Plan): {
|
|
89
|
+
user: string;
|
|
90
|
+
setupUser: string;
|
|
91
|
+
} | undefined;
|
|
87
92
|
export interface SetupOptions {
|
|
88
93
|
repo?: string | undefined;
|
|
89
94
|
commit?: string | undefined;
|
package/dist/devcontainer.js
CHANGED
|
@@ -462,6 +462,7 @@ export function translate(loaded, opts) {
|
|
|
462
462
|
env,
|
|
463
463
|
workspaceFolder,
|
|
464
464
|
user,
|
|
465
|
+
...(remoteUser === undefined ? {} : { remoteUser }),
|
|
465
466
|
lifecycle,
|
|
466
467
|
ports,
|
|
467
468
|
tier,
|
|
@@ -682,6 +683,10 @@ export function wrapCommand(plan, command) {
|
|
|
682
683
|
export function snapshotEnv(plan) {
|
|
683
684
|
return Object.keys(plan.env).length ? { ...plan.env } : undefined;
|
|
684
685
|
}
|
|
686
|
+
export function snapshotUsers(plan) {
|
|
687
|
+
const user = plan.remoteUser ?? plan.user;
|
|
688
|
+
return user === undefined ? undefined : { user, setupUser: "root" };
|
|
689
|
+
}
|
|
685
690
|
export function planSetup(plan, opts = {}) {
|
|
686
691
|
const steps = [];
|
|
687
692
|
if (opts.repo && opts.commit) {
|
package/dist/dirsnap.js
CHANGED
|
@@ -25,7 +25,7 @@ const INTERRUPTED = {
|
|
|
25
25
|
};
|
|
26
26
|
const NOT_WITH_DIR = [
|
|
27
27
|
"--repo", "--commit", "--ref", "--track", "--also-repo", "--image", "--dockerfile", "--context",
|
|
28
|
-
"--devcontainer", "--start", "--
|
|
28
|
+
"--devcontainer", "--start", "--grade", "--holdout", "--grade-score", "--grade-timeout",
|
|
29
29
|
"--grade-output", "--tier",
|
|
30
30
|
];
|
|
31
31
|
export { secretLike };
|
package/dist/errfix.js
CHANGED
|
@@ -106,6 +106,7 @@ function notFoundFor(kind, ctx, apiFix) {
|
|
|
106
106
|
const BILLING_CMD = /`promigence billing (?:card|portal)`/;
|
|
107
107
|
export function withoutBilling(text) {
|
|
108
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}.`)
|
|
109
110
|
.replace(/,? or move to a plan that allows it: `promigence billing (?:card|portal)`\.?/, `, or email ${SUPPORT} for a plan that allows it.`)
|
|
110
111
|
.replace(/or add a card to lift it: `promigence billing (?:card|portal)`/, `or email ${SUPPORT} to lift it`)
|
|
111
112
|
.replace(/adding a card raises it \(owners: `promigence billing (?:card|portal)`\)\.?/, `to raise it, email ${SUPPORT}.`)
|
package/dist/generated.js
CHANGED
|
@@ -83,6 +83,9 @@ export const ERRORS = [
|
|
|
83
83
|
{ code: "aborted_by_client", category: "other", http: 200, exit: 130, billed: "yes",
|
|
84
84
|
message: "sandbox killed by the client",
|
|
85
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." },
|
|
86
89
|
{ code: "expired", category: "other", http: 200, exit: 12, billed: "yes",
|
|
87
90
|
message: "sandbox timeout reached (counted from hand-off)",
|
|
88
91
|
fix: "Raise `--timeout` if the task needs longer." },
|
|
@@ -103,7 +106,7 @@ export const ERRORS = [
|
|
|
103
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." },
|
|
104
107
|
{ code: "forbidden", category: "other", http: 403, exit: 7, billed: "no",
|
|
105
108
|
message: "{detail}",
|
|
106
|
-
fix: "Do what the message names: sign in (`promigence login`), use a key from that org, or ask an owner." },
|
|
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." },
|
|
107
110
|
{ code: "not_found", category: "other", http: 404, exit: 8, billed: "no",
|
|
108
111
|
message: "{kind} `{id}` not found",
|
|
109
112
|
fix: "Check the id; aliases resolve in your org first, then public snapshots (`promigence examples`)." },
|
|
@@ -176,6 +179,9 @@ export const ERRORS = [
|
|
|
176
179
|
{ code: "credit_unclaimed", category: "other", http: 402, exit: 5, billed: "no",
|
|
177
180
|
message: "this account has free credit waiting to be claimed",
|
|
178
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." },
|
|
179
185
|
{ code: "card_required", category: "other", http: 402, exit: 5, billed: "no",
|
|
180
186
|
message: "a card is required for new work since {effective_at}",
|
|
181
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." },
|
|
@@ -185,7 +191,7 @@ export const ERRORS = [
|
|
|
185
191
|
{ code: "concurrency_limit", category: "other", http: 409, exit: 5, billed: "no",
|
|
186
192
|
message: "{live} live + {requested} requested sandboxes is over your limit of {limit}",
|
|
187
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." },
|
|
188
|
-
{ code: "egress_cap_reached", category: "other", http: 403, exit:
|
|
194
|
+
{ code: "egress_cap_reached", category: "other", http: 403, exit: 5, billed: "no",
|
|
189
195
|
message: "monthly data-out cap reached: {used_gb} of {cap_gb} GB",
|
|
190
196
|
fix: "Use `--network none` (still allowed) or wait for the 1st (UTC). For more data out a month, email support@promigence.ai." },
|
|
191
197
|
{ code: "project_cap_reached", category: "cap", http: 403, exit: 5, billed: "no",
|
|
@@ -193,7 +199,10 @@ export const ERRORS = [
|
|
|
193
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>`." },
|
|
194
200
|
{ code: "spend_limit_reached", category: "cap", http: 402, exit: 5, billed: "no",
|
|
195
201
|
message: "today's spend limit {limit} has {remaining} left; this needs {needed}",
|
|
196
|
-
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.
|
|
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." },
|
|
197
206
|
{ code: "tier_over_plan", category: "other", http: 403, exit: 2, billed: "no",
|
|
198
207
|
message: "the {tier} tier ({vcpus} vCPU) is over the {limit} vCPU per-sandbox limit of your {plan} plan",
|
|
199
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`." },
|
|
@@ -233,6 +242,9 @@ export const ERRORS = [
|
|
|
233
242
|
{ code: "key_expired", category: "other", http: 401, exit: 7, billed: "no",
|
|
234
243
|
message: "this API key expired at {expired_at}",
|
|
235
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." },
|
|
236
248
|
];
|
|
237
249
|
export const ERROR_BY_CODE = Object.fromEntries(ERRORS.map((e) => [e.code, e]));
|
|
238
250
|
export const CLIENT_ERRORS = [
|
|
@@ -257,6 +269,9 @@ export const CLIENT_ERRORS = [
|
|
|
257
269
|
{ code: "build_failed", category: "env", http: 0, exit: 3, billed: "no",
|
|
258
270
|
message: "the build could not finish; nothing was stored",
|
|
259
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." },
|
|
260
275
|
{ code: "not_connected", category: "other", http: 0, exit: 7, billed: "no",
|
|
261
276
|
message: "the connection request ended without connecting anything",
|
|
262
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." },
|
package/dist/github.js
CHANGED
|
@@ -14,7 +14,7 @@ function pollMs() {
|
|
|
14
14
|
}
|
|
15
15
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
16
16
|
function notConfigured(s) {
|
|
17
|
-
return usageError(s.message ?? "GitHub
|
|
17
|
+
return usageError(s.message ?? "Connecting GitHub isn't available here yet", "Bring the code in another way: `promigence snapshot create --dir .` uploads the files git tracks here, or clone a public repository in a --setup step.");
|
|
18
18
|
}
|
|
19
19
|
function connectionLine(c) {
|
|
20
20
|
return ` ${c.account} ${c.account_type} · ${c.repository_selection} repositories · installation ${c.installation_id}${c.suspended ? " SUSPENDED on GitHub" : ""}`;
|
|
@@ -107,7 +107,7 @@ const githubStatus = async (ctx) => {
|
|
|
107
107
|
const s = await client(ctx).github.status();
|
|
108
108
|
if (!s.configured) {
|
|
109
109
|
const next = nexts(["promigence snapshot create --dir . --alias app --wait", "bring the files git tracks here instead"]);
|
|
110
|
-
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...s }, next), [`github: ${s.message ?? "GitHub
|
|
110
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...s }, next), [`github: ${s.message ?? "Connecting GitHub isn't available here yet"}`], 0, ctx.pointer);
|
|
111
111
|
}
|
|
112
112
|
const lines = [
|
|
113
113
|
s.connections.length
|
|
@@ -215,7 +215,6 @@ const NOT_WITH_GITHUB = [
|
|
|
215
215
|
["--devcontainer", "it is not read for a connected repository; use --setup steps"],
|
|
216
216
|
["--start", "a background process is part of an image snapshot"],
|
|
217
217
|
["--also-repo", "clone further repositories in a --setup step"],
|
|
218
|
-
["--cpu-class", "the build goes wherever there is room"],
|
|
219
218
|
["--dir", "--dir uploads a local tree instead; pass one of them"],
|
|
220
219
|
];
|
|
221
220
|
const GITHUB_ONLY = ["--ref", "--from", "--track"];
|
package/dist/gitlab.js
CHANGED
|
@@ -12,7 +12,7 @@ function pollMs() {
|
|
|
12
12
|
}
|
|
13
13
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
14
14
|
function notConfigured(s) {
|
|
15
|
-
return usageError(s.message ?? "GitLab
|
|
15
|
+
return usageError(s.message ?? "Connecting GitLab isn't available here yet", "Bring the code in another way: `promigence snapshot create --dir .` uploads the files git tracks here, or clone in a --setup step.");
|
|
16
16
|
}
|
|
17
17
|
function connectionLine(c) {
|
|
18
18
|
return ` ${c.username} on ${c.gitlab_url} · ${c.connection_id}${c.broken ? ` BROKEN: ${c.broken_reason ?? "connect again"}` : ""}`;
|
|
@@ -108,7 +108,7 @@ const gitlabStatus = async (ctx) => {
|
|
|
108
108
|
const s = await client(ctx).gitlab.status();
|
|
109
109
|
if (!s.configured) {
|
|
110
110
|
const next = nexts(["promigence snapshot create --dir . --alias app --wait", "bring the files git tracks here instead"]);
|
|
111
|
-
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...s }, next), [`gitlab: ${s.message ?? "GitLab
|
|
111
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...s }, next), [`gitlab: ${s.message ?? "Connecting GitLab isn't available here yet"}`], 0, ctx.pointer);
|
|
112
112
|
}
|
|
113
113
|
const lines = [
|
|
114
114
|
s.connections.length
|