promigence 0.1.0-beta.13 → 0.1.0-beta.15
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/dist/account.js +57 -23
- package/dist/billing.js +266 -0
- package/dist/bin.js +2 -1
- package/dist/commands.js +2 -2
- package/dist/errfix.js +12 -6
- package/dist/generated.js +23 -8
- package/dist/guide.js +5 -3
- package/dist/handlers.js +10 -1
- package/dist/login.js +4 -4
- package/dist/money.js +8 -0
- package/dist/orgs.js +105 -1
- package/dist/pricing.d.ts +1 -0
- package/dist/pricing.js +6 -2
- package/dist/routes.js +11 -4
- package/dist/sdk/client.d.ts +84 -14
- package/dist/sdk/client.js +125 -33
- package/dist/sdk/core.d.ts +1 -1
- package/dist/sdk/core.js +3 -1
- package/dist/sdk/http2.js +195 -23
- package/dist/sdk/models.gen.d.ts +599 -36
- package/dist/sdk/pty.d.ts +11 -14
- package/dist/sdk/pty.js +13 -11
- package/dist/sdk/trace.js +16 -0
- package/dist/sdk/transport-worker.js +72 -12
- package/dist/surface.d.ts +1 -1
- package/dist/surface.js +80 -6
- package/llms.txt +16 -7
- package/package.json +1 -1
package/dist/account.js
CHANGED
|
@@ -3,6 +3,8 @@ import { queuedLines } from "./capacity.js";
|
|
|
3
3
|
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
|
+
import { autoReloadShort, creditsLine, resumeAllPausedForCredits } from "./billing.js";
|
|
7
|
+
import { dollars } from "./money.js";
|
|
6
8
|
const usd = (n) => n === undefined ? "—" : `$${n.toFixed(n < 0.01 && n > 0 ? 4 : 2)}`;
|
|
7
9
|
export const PAYMENT_METHOD_NAMES = {
|
|
8
10
|
apple_pay: "Apple Pay",
|
|
@@ -115,10 +117,10 @@ const me = async (ctx) => {
|
|
|
115
117
|
lines.push(` plan: ${plan}${trial?.on_trial ? " (trial)" : ""}`);
|
|
116
118
|
if (conc)
|
|
117
119
|
lines.push(` concurrency: ${concurrencyText(conc)}`);
|
|
118
|
-
if (trial
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
if (trial) {
|
|
121
|
+
const available = trial.credits_available ?? trial.credits_remaining;
|
|
122
|
+
const held = trial.credits_reserved ?? 0;
|
|
123
|
+
lines.push(` credits: ${dollars(available)} available${held > 0 ? ` (${dollars(held)} held by running work)` : ""}`);
|
|
122
124
|
}
|
|
123
125
|
if (typeof info.spend === "number") {
|
|
124
126
|
const kinds = Object.entries(info.spend_detail?.by_kind ?? {}).filter(([, v]) => v > 0);
|
|
@@ -213,7 +215,7 @@ const billingUsage = async (ctx) => {
|
|
|
213
215
|
? [["promigence me", "your limits, concurrency and trial credit"]]
|
|
214
216
|
: b.card_on_file
|
|
215
217
|
? [["promigence billing portal", "the card on file and past invoices"]]
|
|
216
|
-
: [["promigence billing card", "an owner adds a card
|
|
218
|
+
: [["promigence billing card", "an owner adds a card"]]), ...(moreLedger.length ? moreLedger : [["promigence billing usage --ledger", "this key's project's metered rows"]]));
|
|
217
219
|
const plan = planName(me, b);
|
|
218
220
|
const onTrial = (b.trial?.on_trial ?? me?.trial?.on_trial) === true;
|
|
219
221
|
const env = okEnvelope(ctx.cmd.name, {
|
|
@@ -255,22 +257,26 @@ const billingUsage = async (ctx) => {
|
|
|
255
257
|
lines.push(` ${k}: ${detail(row)}`);
|
|
256
258
|
}
|
|
257
259
|
if (typeof usage["credits_applied"] === "number" && usage["credits_applied"] > 0) {
|
|
258
|
-
lines.push(` paid
|
|
260
|
+
lines.push(` paid from credits: ${usd(usage["credits_applied"])}`);
|
|
259
261
|
}
|
|
260
262
|
const trial = b.trial;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
263
|
+
const credits = creditsLine(b.credits) ?? (trial?.credits_remaining === undefined ? undefined : `credits: ${dollars(trial.credits_remaining)} available`);
|
|
264
|
+
if (credits)
|
|
265
|
+
lines.push(` ${credits}`);
|
|
266
|
+
if (b.auto_reload)
|
|
267
|
+
lines.push(` auto-reload: ${autoReloadShort(b.auto_reload)}`);
|
|
268
|
+
lines.push(` card: ${b.card_on_file ? paymentMethodText(b.card) : `none on file${billingOff ? " (payments are not open yet)" : ""}`}`);
|
|
264
269
|
if (b.card_note)
|
|
265
270
|
lines.push(` ${b.card_note}`);
|
|
266
|
-
|
|
271
|
+
const invoiceComes = b.plan_status === undefined || !!b.plan_status.renews_at || b.model === "postpaid";
|
|
272
|
+
if (invoiceComes && b.upcoming_invoice?.amount_due !== undefined && b.upcoming_invoice?.amount_due !== null) {
|
|
267
273
|
lines.push(` next invoice: ${usd(b.upcoming_invoice.amount_due)}`);
|
|
268
274
|
}
|
|
269
|
-
else if (b.upcoming_invoice_error) {
|
|
275
|
+
else if (invoiceComes && b.upcoming_invoice_error) {
|
|
270
276
|
lines.push(` next invoice: not available (${b.upcoming_invoice_error})`);
|
|
271
277
|
}
|
|
272
278
|
if (b.suspended)
|
|
273
|
-
lines.push(` SUSPENDED: ${b.suspend_reason ?? "see promigence billing
|
|
279
|
+
lines.push(` SUSPENDED: ${b.suspend_reason ?? "see promigence billing"}`);
|
|
274
280
|
for (const e of entries) {
|
|
275
281
|
lines.push(` ${e.created_at ?? ""} ${e.kind}${e.tier ? ` ${e.tier}` : ""} ${usd(e.amount)}${e.seconds ? ` · ${e.seconds}s` : ""}${e.run_id ? ` · ${e.run_id}` : ""}`);
|
|
276
282
|
}
|
|
@@ -294,12 +300,19 @@ const CREDIT_WHAT = {
|
|
|
294
300
|
from_promigence: "Credit from Promigence",
|
|
295
301
|
service_restart: "Credit for a service restart",
|
|
296
302
|
confirmation_credit: "Credit for the $1 confirmation",
|
|
303
|
+
credits_bought: "Credits bought",
|
|
304
|
+
auto_reload: "Auto-reload",
|
|
305
|
+
credit_taken_back: "Credit taken back",
|
|
306
|
+
credit_regranted: "Credit given back",
|
|
297
307
|
};
|
|
298
308
|
const CREDIT_ENDED = { used: "used", expired: "expired", taken_back: "taken back" };
|
|
299
309
|
const PAYMENT_WHAT = {
|
|
300
310
|
invoice_paid: "Invoice paid",
|
|
301
311
|
payment_failed: "Payment failed",
|
|
302
312
|
refund: "Refund",
|
|
313
|
+
credits_bought: "Credits bought",
|
|
314
|
+
auto_reload: "Auto-reload",
|
|
315
|
+
dispute_repaid: "Repayment",
|
|
303
316
|
};
|
|
304
317
|
const PAYMENT_STATUS = {
|
|
305
318
|
paid: "paid",
|
|
@@ -323,15 +336,30 @@ export function historyLines(entries) {
|
|
|
323
336
|
if (!p)
|
|
324
337
|
return ` ${day} (a row this version cannot show: see --json)`;
|
|
325
338
|
const check = p.kind === "method_check";
|
|
339
|
+
const planFee = p.kind === "plan_invoice";
|
|
326
340
|
const what = check
|
|
327
341
|
? `$${Number.isInteger(p.amount_usd) ? String(p.amount_usd) : p.amount_usd.toFixed(2)} to confirm ${p.method || "your payment method"}`
|
|
328
|
-
:
|
|
329
|
-
|
|
342
|
+
: planFee
|
|
343
|
+
? `Plan: ${p.plan ?? "your plan"}`
|
|
344
|
+
: (wordFor(PAYMENT_WHAT, p.kind) ?? "Payment");
|
|
345
|
+
const detail = [p.plan && !planFee ? `${p.plan} plan` : null, p.invoice_number ? `invoice ${p.invoice_number}` : null]
|
|
330
346
|
.filter(Boolean)
|
|
331
347
|
.join(", ");
|
|
332
348
|
const status = check && p.status === "failed" ? "failed" : (wordFor(PAYMENT_STATUS, p.status) ?? p.status);
|
|
333
|
-
const
|
|
334
|
-
const
|
|
349
|
+
const https = (u) => (typeof u === "string" && u.startsWith("https://") ? u : null);
|
|
350
|
+
const linked = [
|
|
351
|
+
https(p.invoice_pdf) ? `invoice ${p.invoice_pdf}` : null,
|
|
352
|
+
https(p.receipt_url) ? `receipt ${p.receipt_url}` : null,
|
|
353
|
+
https(p.pay_url) ? `pay at ${p.pay_url}` : null,
|
|
354
|
+
].filter(Boolean);
|
|
355
|
+
const url = https(p.invoice_url);
|
|
356
|
+
const link = check
|
|
357
|
+
? ""
|
|
358
|
+
: linked.length
|
|
359
|
+
? ` · ${linked.join(" · ")}`
|
|
360
|
+
: url
|
|
361
|
+
? ` · ${unpaid(p.status) ? "pay at" : "receipt"} ${url}`
|
|
362
|
+
: "";
|
|
335
363
|
return ` ${day} ${what}${detail ? ` (${detail})` : ""} ${usd(p.amount_usd)} ${status}${link}`;
|
|
336
364
|
});
|
|
337
365
|
}
|
|
@@ -378,11 +406,11 @@ const referrals = async (ctx) => {
|
|
|
378
406
|
const o = r.offer;
|
|
379
407
|
lines.push(`promigence referrals: ${o.headline}`);
|
|
380
408
|
lines.push(` your code: ${r.code} (a friend signs up with: ${sh `promigence login --ref ${r.code}`})`);
|
|
381
|
-
lines.push(` they get ${usd(o.give_usd)} of compute credit
|
|
382
|
-
`${o.qualifying_plans.length ? `
|
|
383
|
-
`${o.hold_days > 0 ? `${o.hold_days} day
|
|
409
|
+
lines.push(` they get ${usd(o.give_usd)} of compute credit once they first pay at least ${usd(o.give_usd)}, for credits or a plan` +
|
|
410
|
+
`${o.qualifying_plans.length ? ` (plans: ${o.qualifying_plans.join(" / ")})` : ""}; you get ${usd(o.get_usd)} ` +
|
|
411
|
+
`${o.hold_days > 0 ? `${o.hold_days} ${o.hold_days === 1 ? "day" : "days"} later` : "then"}`);
|
|
384
412
|
if (o.credit_expiry_days !== null)
|
|
385
|
-
lines.push(` credit lasts ${o.credit_expiry_days} day
|
|
413
|
+
lines.push(` credit lasts ${o.credit_expiry_days} ${o.credit_expiry_days === 1 ? "day" : "days"} from its grant`);
|
|
386
414
|
if (o.ends_at)
|
|
387
415
|
lines.push(` offer ends ${o.ends_at}`);
|
|
388
416
|
}
|
|
@@ -405,8 +433,8 @@ const referralsApply = async (ctx) => {
|
|
|
405
433
|
? [`promigence referrals apply: ${r.code} recorded; it is being checked before any credit is granted`]
|
|
406
434
|
: [
|
|
407
435
|
`promigence referrals apply: ${r.code} applied`,
|
|
408
|
-
` you get ${usd(r.reward_usd)} of compute credit
|
|
409
|
-
`${r.qualifying_plans.length ? `
|
|
436
|
+
` you get ${usd(r.reward_usd)} of compute credit once you first pay at least ${usd(r.reward_usd)}, for credits or a plan` +
|
|
437
|
+
`${r.qualifying_plans.length ? ` (plans: ${r.qualifying_plans.join(" / ")})` : ""}`,
|
|
410
438
|
];
|
|
411
439
|
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...r }, next), lines, 0, ctx.pointer);
|
|
412
440
|
};
|
|
@@ -636,7 +664,7 @@ const sandboxInfo = async (ctx) => {
|
|
|
636
664
|
const limitNext = s.pause_reason === "spend_cap"
|
|
637
665
|
? [[sh `promigence sandbox resume ${sid} --cap USD`, "raise its run's cap and go on (paused time is not billed)"]]
|
|
638
666
|
: s.pause_reason === "credits_exhausted"
|
|
639
|
-
? [["promigence billing
|
|
667
|
+
? [["promigence billing buy USD", "add credits, then resume it"], [sh `promigence sandbox resume ${sid}`, "go on once credits are added"]]
|
|
640
668
|
: [];
|
|
641
669
|
const next = nexts(...limitNext, ...(execs.length ? [[sh `promigence exec output ${execs[execs.length - 1].exec_id} --sandbox ${sid}`, "what its last command printed"]] : []), ...(ended
|
|
642
670
|
? (s.run_id ? [[sh `promigence run report ${s.run_id} --sandbox ${sid}`, "how it ended, in its run's report"]] : [])
|
|
@@ -684,6 +712,12 @@ const sandboxPause = async (ctx) => {
|
|
|
684
712
|
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...res, sandbox_id: sid, state: "paused" }, next), lines, 0, ctx.pointer);
|
|
685
713
|
};
|
|
686
714
|
const sandboxResume = async (ctx) => {
|
|
715
|
+
if (bool(ctx, "--all-paused-for-credits")) {
|
|
716
|
+
if (ctx.args[0] !== undefined) {
|
|
717
|
+
throw usageError("--all-paused-for-credits takes no sandbox id", "Pass a sandbox id, or --all-paused-for-credits alone.");
|
|
718
|
+
}
|
|
719
|
+
return resumeAllPausedForCredits(ctx);
|
|
720
|
+
}
|
|
687
721
|
const sid = positional(ctx, "a sandbox id", "promigence sandbox resume sbx_01");
|
|
688
722
|
const optimizeFor = optimizeForFlag(ctx);
|
|
689
723
|
const cap = str(ctx, "--cap");
|
package/dist/billing.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { bool, client, nexts, str, waitBound } from "./commands.js";
|
|
2
|
+
import { emit, errorEnvelope, okEnvelope, parseUsd, usageError } from "./io.js";
|
|
3
|
+
import { dollars } from "./money.js";
|
|
4
|
+
import { PromigenceError, TimeoutError } from "./sdk/index.js";
|
|
5
|
+
import { sh } from "./term.js";
|
|
6
|
+
export const BILLING_PAGE = "https://console.promigence.ai/settings/org/billing";
|
|
7
|
+
export const MIN_PURCHASE_USD = 5;
|
|
8
|
+
export function cardWords(card) {
|
|
9
|
+
const NAMES = {
|
|
10
|
+
visa: "Visa", mastercard: "Mastercard", amex: "American Express", discover: "Discover", diners: "Diners Club",
|
|
11
|
+
jcb: "JCB", unionpay: "UnionPay", apple_pay: "Apple Pay", google_pay: "Google Pay", link: "Link",
|
|
12
|
+
cashapp: "Cash App Pay", amazon_pay: "Amazon Pay",
|
|
13
|
+
};
|
|
14
|
+
const brand = card?.brand ?? "";
|
|
15
|
+
const named = brand ? (Object.prototype.hasOwnProperty.call(NAMES, brand) ? NAMES[brand] : brand) : "";
|
|
16
|
+
const last4 = card?.last4 ?? "";
|
|
17
|
+
if (named && last4)
|
|
18
|
+
return `your ${named} ending ${last4}`;
|
|
19
|
+
if (named)
|
|
20
|
+
return `your ${named}`;
|
|
21
|
+
if (last4)
|
|
22
|
+
return `your card ending ${last4}`;
|
|
23
|
+
return "your card";
|
|
24
|
+
}
|
|
25
|
+
export function dateWords(at) {
|
|
26
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(at ?? "");
|
|
27
|
+
const MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
28
|
+
if (!m)
|
|
29
|
+
return at ?? "";
|
|
30
|
+
const month = MONTHS[Number(m[2]) - 1];
|
|
31
|
+
return month ? `${Number(m[3])} ${month} ${m[1]}` : (at ?? "");
|
|
32
|
+
}
|
|
33
|
+
const PAUSED_PAYMENT = {
|
|
34
|
+
declined: "the card was declined",
|
|
35
|
+
authentication_required: "your bank asks you to confirm the payment",
|
|
36
|
+
};
|
|
37
|
+
const LOWER_IT = "promigence billing auto-reload --on --below <usd> --add <usd> --accept";
|
|
38
|
+
export function autoReloadLines(a, trust) {
|
|
39
|
+
if (!a)
|
|
40
|
+
return ["Auto-reload is off."];
|
|
41
|
+
if (a.unavailable_reason === "card_country") {
|
|
42
|
+
return ["Auto-reload isn't available yet for cards issued in India. Top up by hand: promigence billing buy <usd>."];
|
|
43
|
+
}
|
|
44
|
+
if (a.paused_reason) {
|
|
45
|
+
switch (a.paused_reason) {
|
|
46
|
+
case "declined":
|
|
47
|
+
case "authentication_required": {
|
|
48
|
+
const pay = a.last?.pay_url ? ` (${a.last.pay_url})` : "";
|
|
49
|
+
return [`Auto-reload is paused: ${PAUSED_PAYMENT[a.paused_reason]}. Finish the payment${pay} or add credits to turn it back on.`];
|
|
50
|
+
}
|
|
51
|
+
case "daily_limit":
|
|
52
|
+
return ["Auto-reload is paused: it starts again tomorrow (UTC)."];
|
|
53
|
+
case "disputed":
|
|
54
|
+
return ["Auto-reload is paused while a payment for this organization is disputed."];
|
|
55
|
+
case "amount_over_limit":
|
|
56
|
+
return [`Auto-reload is paused: its amount is above this organization's limit (${dollars(trust?.reload_max_usd)}). Lower it: ${LOWER_IT}`];
|
|
57
|
+
case "support":
|
|
58
|
+
return ["Auto-reload is paused by Promigence support. Write to support@promigence.ai to turn it back on."];
|
|
59
|
+
default:
|
|
60
|
+
return [`Auto-reload is paused: ${a.paused_reason}.`];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!a.on)
|
|
64
|
+
return ["Auto-reload is off."];
|
|
65
|
+
return [`Auto-reload is on: when available credits fall below ${dollars(a.threshold_usd)}, add ${dollars(a.amount_usd)} from ${cardWords(a.card)}.`];
|
|
66
|
+
}
|
|
67
|
+
export function autoReloadShort(a) {
|
|
68
|
+
if (!a || !a.on)
|
|
69
|
+
return "off";
|
|
70
|
+
const base = `below ${dollars(a.threshold_usd)}, add ${dollars(a.amount_usd)}`;
|
|
71
|
+
return a.paused_reason ? `${base} (paused: ${a.paused_reason.replaceAll("_", " ")})` : base;
|
|
72
|
+
}
|
|
73
|
+
export function creditsLine(c) {
|
|
74
|
+
if (!c)
|
|
75
|
+
return undefined;
|
|
76
|
+
return `credits: ${dollars(c.available_usd)} available${c.held_usd > 0 ? ` (${dollars(c.held_usd)} held by running work)` : ""}`;
|
|
77
|
+
}
|
|
78
|
+
const billing = async (ctx) => {
|
|
79
|
+
const c = client(ctx);
|
|
80
|
+
const [b, me] = await Promise.all([c.billing.usage(), c.me().catch(() => undefined)]);
|
|
81
|
+
const org = me?.org && me.org !== me.org_id ? me.org : (b.org_id ?? me?.org_id ?? "org");
|
|
82
|
+
const lines = [`promigence billing: ${org}`];
|
|
83
|
+
const plan = b.plan_status;
|
|
84
|
+
if (plan?.name)
|
|
85
|
+
lines.push(` plan: ${plan.name}${plan.renews_at ? ` (renews ${dateWords(plan.renews_at)})` : ""}`);
|
|
86
|
+
if (plan?.renewal) {
|
|
87
|
+
const said = plan.renewal.state === "action_required"
|
|
88
|
+
? `Your bank asks you to confirm the ${plan.name} payment.`
|
|
89
|
+
: `Your ${plan.name} renewal did not go through.${plan.renewal.next_try_at ? ` We try again on ${dateWords(plan.renewal.next_try_at)}.` : ""}`;
|
|
90
|
+
lines.push(` renewal: ${said}${plan.renewal.pay_url ? ` ${plan.renewal.pay_url}` : ""}`);
|
|
91
|
+
}
|
|
92
|
+
if (b.credits)
|
|
93
|
+
lines.push(` credits: ${dollars(b.credits.available_usd)} available`);
|
|
94
|
+
if (b.model === "postpaid" && b.switch) {
|
|
95
|
+
lines.push(` moves to credits on ${dateWords(b.switch.at)} (${dollars(b.switch.credits_waiting_usd)} ready)`);
|
|
96
|
+
}
|
|
97
|
+
lines.push(` auto-reload: ${autoReloadShort(b.auto_reload)}`);
|
|
98
|
+
if (b.hold)
|
|
99
|
+
lines.push(` on hold: ${b.hold.reason}: ${b.hold.url ?? BILLING_PAGE}`);
|
|
100
|
+
lines.push(` change plan: ${BILLING_PAGE}`);
|
|
101
|
+
const next = nexts(...(b.hold?.dispute_id ? [[sh `promigence billing repay ${b.hold.dispute_id}`, "repay the disputed payment, which lifts the hold"]] : []), ["promigence billing buy USD", "add credits on a payment page"], ["promigence billing auto-reload", "add credits from the saved card when available credits run low"], ["promigence billing usage", "this month's spend"]);
|
|
102
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { billing: b }, next), lines, 0, ctx.pointer);
|
|
103
|
+
};
|
|
104
|
+
const FINAL = new Set(["paid", "paid_awaiting_switch", "expired", "failed"]);
|
|
105
|
+
const delay = (msMs) => new Promise((r) => setTimeout(r, msMs));
|
|
106
|
+
function settledLine(s) {
|
|
107
|
+
switch (s.state) {
|
|
108
|
+
case "paid":
|
|
109
|
+
return `${dollars(s.amount_usd)} of credits added.${s.available_usd === undefined || s.available_usd === null ? "" : ` Available: ${dollars(s.available_usd)}.`}`;
|
|
110
|
+
case "paid_awaiting_switch":
|
|
111
|
+
return `${dollars(s.amount_usd)} of credits are ready on ${dateWords(s.switch_at)}.`;
|
|
112
|
+
case "expired":
|
|
113
|
+
return "No payment was made.";
|
|
114
|
+
case "failed":
|
|
115
|
+
return "The payment did not go through. No credits were added.";
|
|
116
|
+
default:
|
|
117
|
+
return "Payment received. Your credits will appear in a minute.";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const billingBuy = async (ctx) => {
|
|
121
|
+
const c = client(ctx);
|
|
122
|
+
const session = str(ctx, "--session");
|
|
123
|
+
const bound = waitBound(ctx);
|
|
124
|
+
let page;
|
|
125
|
+
if (session === undefined) {
|
|
126
|
+
const raw = ctx.args[0];
|
|
127
|
+
if (raw === undefined)
|
|
128
|
+
throw usageError("billing buy needs an amount in dollars", "Example: promigence billing buy 50.");
|
|
129
|
+
const amount = parseUsd(raw.replace(/^\$/, ""), "USD");
|
|
130
|
+
if (amount < MIN_PURCHASE_USD) {
|
|
131
|
+
throw usageError(`promigence billing buy: the smallest purchase is ${dollars(MIN_PURCHASE_USD)}.`, "Choose an amount from $5 to $10,000.");
|
|
132
|
+
}
|
|
133
|
+
page = await c.billing.buyCredits(amount);
|
|
134
|
+
process.stderr.write(`promigence billing buy: open this page to pay ${dollars(page.amount_usd)} for credits:\n ${page.url}\n`);
|
|
135
|
+
if (bool(ctx, "--no-wait")) {
|
|
136
|
+
const next = nexts([sh `promigence billing buy --session ${page.session_id}`, "check the payment and add its credits"]);
|
|
137
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { page }, next), [
|
|
138
|
+
`promigence billing buy: open this page to pay ${dollars(page.amount_usd)} for credits:`,
|
|
139
|
+
` ${page.url}`,
|
|
140
|
+
], 0, ctx.pointer);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const id = session ?? page.session_id;
|
|
144
|
+
const settle = () => c.billing.settleCredits(id);
|
|
145
|
+
const until = Date.now() + bound;
|
|
146
|
+
if (page)
|
|
147
|
+
process.stderr.write("Waiting for the payment (Ctrl-C stops waiting; a payment still counts)\n");
|
|
148
|
+
let s = await settle();
|
|
149
|
+
while (!FINAL.has(s.state) && Date.now() < until) {
|
|
150
|
+
await delay(Math.min(2000, Math.max(0, until - Date.now())));
|
|
151
|
+
s = await settle();
|
|
152
|
+
}
|
|
153
|
+
if (!FINAL.has(s.state)) {
|
|
154
|
+
const err = new TimeoutError(`the payment page was not paid within the ${Math.round(bound / 1000)} s wait; nothing was charged by this command`, `A payment on the page still counts. Check it: ${sh `promigence billing buy --session ${id}`}.`);
|
|
155
|
+
const next = nexts([sh `promigence billing buy --session ${id}`, "check the payment and add its credits"]);
|
|
156
|
+
return emit(ctx.mode, { ...errorEnvelope(ctx.cmd.name, err, next), ...(page ? { page } : {}), settle: s }, [`promigence billing buy: ${err.message}`, ` ${err.fix}`], 11, ctx.pointer);
|
|
157
|
+
}
|
|
158
|
+
const ok = s.state === "paid" || s.state === "paid_awaiting_switch";
|
|
159
|
+
const next = ok
|
|
160
|
+
? nexts(["promigence billing", "the credits, auto-reload and the plan"])
|
|
161
|
+
: nexts(["promigence billing buy USD", "open a new payment page"]);
|
|
162
|
+
const line = settledLine(s);
|
|
163
|
+
if (!ok) {
|
|
164
|
+
const err = new PromigenceError({ code: "usage", message: line, fix: "Open a new payment page: promigence billing buy <usd>.", exitCode: 2 });
|
|
165
|
+
return emit(ctx.mode, { ...errorEnvelope(ctx.cmd.name, err, next), settle: s }, [`promigence billing buy: ${line}`], 2, ctx.pointer);
|
|
166
|
+
}
|
|
167
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...(page ? { page } : {}), settle: s }, next), [line], 0, ctx.pointer);
|
|
168
|
+
};
|
|
169
|
+
export function authorizationText(b, threshold, amount) {
|
|
170
|
+
const a = b.auto_reload;
|
|
171
|
+
const template = a?.authorization?.template ?? "";
|
|
172
|
+
return template
|
|
173
|
+
.replaceAll("{card}", cardWords(a?.card))
|
|
174
|
+
.replaceAll("{amount}", dollars(amount))
|
|
175
|
+
.replaceAll("{threshold}", dollars(threshold))
|
|
176
|
+
.replaceAll("{n}", String(b.trust?.reloads_per_day ?? ""))
|
|
177
|
+
.replaceAll("{day_max}", dollars(b.trust?.per_day_max_usd));
|
|
178
|
+
}
|
|
179
|
+
const billingAutoReload = async (ctx) => {
|
|
180
|
+
const c = client(ctx);
|
|
181
|
+
const on = bool(ctx, "--on");
|
|
182
|
+
const off = bool(ctx, "--off");
|
|
183
|
+
const below = str(ctx, "--below");
|
|
184
|
+
const add = str(ctx, "--add");
|
|
185
|
+
if (on && off)
|
|
186
|
+
throw usageError("--on and --off together", "Pass one of them.");
|
|
187
|
+
if (!on && (below !== undefined || add !== undefined || bool(ctx, "--accept"))) {
|
|
188
|
+
throw usageError("--below, --add and --accept go with --on", "Example: promigence billing auto-reload --on --below 10 --add 50 --accept.");
|
|
189
|
+
}
|
|
190
|
+
const next = nexts(["promigence billing", "the credits and the plan"]);
|
|
191
|
+
if (!on && !off) {
|
|
192
|
+
const a = await c.billing.autoReload();
|
|
193
|
+
const trust = a.paused_reason === "amount_over_limit" ? (await c.billing.usage()).trust : undefined;
|
|
194
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { auto_reload: a }, next), autoReloadLines(a, trust), 0, ctx.pointer);
|
|
195
|
+
}
|
|
196
|
+
if (off) {
|
|
197
|
+
const a = await c.billing.setAutoReload({ on: false });
|
|
198
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { auto_reload: a }, next), autoReloadLines(a), 0, ctx.pointer);
|
|
199
|
+
}
|
|
200
|
+
const b = await c.billing.usage();
|
|
201
|
+
if (b.auto_reload?.unavailable_reason === "card_country") {
|
|
202
|
+
throw usageError("Auto-reload isn't available yet for cards issued in India.", "Top up by hand: promigence billing buy <usd>.");
|
|
203
|
+
}
|
|
204
|
+
const threshold = below === undefined ? (b.auto_reload?.threshold_usd ?? 10) : parseUsd(below, "--below");
|
|
205
|
+
const amount = add === undefined ? (b.auto_reload?.amount_usd ?? 50) : parseUsd(add, "--add");
|
|
206
|
+
if (!bool(ctx, "--accept")) {
|
|
207
|
+
throw usageError(authorizationText(b, threshold, amount), "Pass --accept to agree.");
|
|
208
|
+
}
|
|
209
|
+
const a = await c.billing.setAutoReload({
|
|
210
|
+
on: true,
|
|
211
|
+
thresholdUsd: threshold,
|
|
212
|
+
amountUsd: amount,
|
|
213
|
+
...(b.auto_reload?.authorization?.version === undefined ? {} : { authorizationVersion: b.auto_reload.authorization.version }),
|
|
214
|
+
});
|
|
215
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { auto_reload: a }, next), autoReloadLines(a, b.trust), 0, ctx.pointer);
|
|
216
|
+
};
|
|
217
|
+
const billingHolds = async (ctx) => {
|
|
218
|
+
const h = await client(ctx).billing.holds();
|
|
219
|
+
const n = h.sandboxes.length;
|
|
220
|
+
const lines = [`promigence billing holds: ${dollars(h.held_usd)} held by ${n} ${n === 1 ? "sandbox" : "sandboxes"}`];
|
|
221
|
+
for (const s of h.sandboxes) {
|
|
222
|
+
lines.push(` ${s.sandbox_id} ${dollars(s.held_usd)} ${s.state === "paused" || !s.ends_at ? "paused" : `ends ${s.ends_at}`}`);
|
|
223
|
+
}
|
|
224
|
+
for (const b of h.builds)
|
|
225
|
+
lines.push(` ${b.build_id} ${dollars(b.held_usd)} build`);
|
|
226
|
+
if (h.data_out_usd > 0)
|
|
227
|
+
lines.push(` data out not yet charged ${dollars(h.data_out_usd)}`);
|
|
228
|
+
if (h.storage_usd > 0)
|
|
229
|
+
lines.push(` storage, the next 7 days ${dollars(h.storage_usd)}`);
|
|
230
|
+
const first = h.sandboxes[0];
|
|
231
|
+
const next = first
|
|
232
|
+
? nexts([sh `promigence sandbox kill ${first.sandbox_id}`, "end it, and free what it holds"], [sh `promigence sandbox extend ${first.sandbox_id} --timeout DUR`, "change its lifetime (a shorter one holds less)"])
|
|
233
|
+
: nexts(["promigence billing", "the credits and the plan"]);
|
|
234
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { holds: h }, next), lines, 0, ctx.pointer);
|
|
235
|
+
};
|
|
236
|
+
const billingRepay = async (ctx) => {
|
|
237
|
+
const dispute = ctx.args[0];
|
|
238
|
+
if (dispute === undefined) {
|
|
239
|
+
throw usageError("billing repay needs a dispute id", "`promigence billing` names the hold; its dispute id is in `promigence billing --json` (hold.dispute_id).");
|
|
240
|
+
}
|
|
241
|
+
const page = await client(ctx).billing.repayDispute(dispute);
|
|
242
|
+
const next = nexts(["promigence billing", "once it is paid: the hold is lifted"]);
|
|
243
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { page }, next), [
|
|
244
|
+
`promigence billing repay: open this page to repay ${dollars(page.amount_usd)}:`,
|
|
245
|
+
` ${page.url}`,
|
|
246
|
+
], 0, ctx.pointer);
|
|
247
|
+
};
|
|
248
|
+
export const BILLING_HANDLERS = {
|
|
249
|
+
billing,
|
|
250
|
+
"billing repay": billingRepay,
|
|
251
|
+
"billing buy": billingBuy,
|
|
252
|
+
"billing auto-reload": billingAutoReload,
|
|
253
|
+
"billing holds": billingHolds,
|
|
254
|
+
};
|
|
255
|
+
export async function resumeAllPausedForCredits(ctx) {
|
|
256
|
+
const r = await client(ctx).sandboxes.resumePausedForCredits();
|
|
257
|
+
const n = r.resumed.length;
|
|
258
|
+
const m = r.still_need_credits.length;
|
|
259
|
+
const line = m > 0
|
|
260
|
+
? `${n} resumed. ${m} still need credits: add credits with promigence billing buy <usd>.`
|
|
261
|
+
: `${n} resumed. ${m} still need credits.`;
|
|
262
|
+
const next = m > 0
|
|
263
|
+
? nexts(["promigence billing buy USD", "add credits, then resume the rest"])
|
|
264
|
+
: nexts(["promigence sandbox list", "your sandboxes"]);
|
|
265
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...r }, next), [line], 0, ctx.pointer);
|
|
266
|
+
}
|
package/dist/bin.js
CHANGED
|
@@ -18,6 +18,7 @@ import { RUNNERS_HANDLERS } from "./runners.js";
|
|
|
18
18
|
import { PRICING_HANDLERS } from "./pricing.js";
|
|
19
19
|
import { GITHUB_HANDLERS } from "./github.js";
|
|
20
20
|
import { GITLAB_HANDLERS } from "./gitlab.js";
|
|
21
|
+
import { BILLING_HANDLERS } from "./billing.js";
|
|
21
22
|
import { emit, errorEnvelope, errorTextLines, parseDuration, setBeforeExit, toPromigenceError, usageError as usageFailure, USAGE_DOCS, write, } from "./io.js";
|
|
22
23
|
import { setCaller } from "./sdk/caller.js";
|
|
23
24
|
import { sh } from "./term.js";
|
|
@@ -270,7 +271,7 @@ async function main(argv) {
|
|
|
270
271
|
await write(process.stdout, renderCommandHelp(cmd));
|
|
271
272
|
return;
|
|
272
273
|
}
|
|
273
|
-
const handler = HANDLERS[cmd.name] ?? EXTRA_HANDLERS[cmd.name] ?? BUNDLE_HANDLERS[cmd.name] ?? LOGIN_HANDLERS[cmd.name] ?? ORG_HANDLERS[cmd.name] ?? LIVE_HANDLERS[cmd.name] ?? SSH_HANDLERS[cmd.name] ?? ACCOUNT_HANDLERS[cmd.name] ?? MCP_HANDLERS[cmd.name] ?? AGENT_HANDLERS[cmd.name] ?? CREDITS_HANDLERS[cmd.name] ?? RUNNERS_HANDLERS[cmd.name] ?? PRICING_HANDLERS[cmd.name] ?? GITHUB_HANDLERS[cmd.name] ?? GITLAB_HANDLERS[cmd.name] ?? TEMPLATES_HANDLERS[cmd.name];
|
|
274
|
+
const handler = HANDLERS[cmd.name] ?? EXTRA_HANDLERS[cmd.name] ?? BUNDLE_HANDLERS[cmd.name] ?? LOGIN_HANDLERS[cmd.name] ?? ORG_HANDLERS[cmd.name] ?? LIVE_HANDLERS[cmd.name] ?? SSH_HANDLERS[cmd.name] ?? ACCOUNT_HANDLERS[cmd.name] ?? MCP_HANDLERS[cmd.name] ?? AGENT_HANDLERS[cmd.name] ?? CREDITS_HANDLERS[cmd.name] ?? RUNNERS_HANDLERS[cmd.name] ?? PRICING_HANDLERS[cmd.name] ?? GITHUB_HANDLERS[cmd.name] ?? GITLAB_HANDLERS[cmd.name] ?? TEMPLATES_HANDLERS[cmd.name] ?? BILLING_HANDLERS[cmd.name];
|
|
274
275
|
if (!handler)
|
|
275
276
|
return void (await notReleased(mode, cmd));
|
|
276
277
|
const ctx = {
|
package/dist/commands.js
CHANGED
|
@@ -1864,7 +1864,7 @@ const runComposite = async (ctx) => {
|
|
|
1864
1864
|
const next = nexts(...(capPaused
|
|
1865
1865
|
? [limitPauseOf(capPaused) === "spend_cap"
|
|
1866
1866
|
? [sh `promigence sandbox resume ${capPaused.sandbox_id} --cap USD`, "go on: a cap above the run's (its files and state are kept)"]
|
|
1867
|
-
: ["promigence billing
|
|
1867
|
+
: ["promigence billing buy USD", `add credits, then ${sh `promigence sandbox resume ${capPaused.sandbox_id}`}`]]
|
|
1868
1868
|
: []), [sh `promigence run report ${runId} --json`, "the full validity report (per-sandbox evidence)"], ...((report.totals?.env_failed ?? 0) > 0
|
|
1869
1869
|
? [[sh `promigence run replay ${runId}`, "re-fork the env failures (a replay is a new sandbox, billed like any other)"]]
|
|
1870
1870
|
: []), ...(kept.length
|
|
@@ -2062,7 +2062,7 @@ export function limitPauseLines(report) {
|
|
|
2062
2062
|
}
|
|
2063
2063
|
else {
|
|
2064
2064
|
lines.push(` ${s.sandbox_id}: paused: the organization's credits ran out; its files and state are kept`);
|
|
2065
|
-
lines.push(` go on: add
|
|
2065
|
+
lines.push(` go on: add credits (owners: promigence billing buy <usd>), then ${sh `promigence sandbox resume ${s.sandbox_id}`}, or end it: ${sh `promigence sandbox kill ${s.sandbox_id}`}`);
|
|
2066
2066
|
}
|
|
2067
2067
|
}
|
|
2068
2068
|
if (paused.length > FAILURES_SHOWN) {
|
package/dist/errfix.js
CHANGED
|
@@ -103,18 +103,24 @@ function notFoundFor(kind, ctx, apiFix) {
|
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
const BILLING_CMD = /`promigence billing (?:card|portal)
|
|
106
|
+
const BILLING_CMD = /`promigence billing (?:card|portal|buy <usd>)`|Change plan in Billing/;
|
|
107
107
|
export function withoutBilling(text) {
|
|
108
|
+
const more = `Payments are not open yet: for more credits, email ${SUPPORT}.`;
|
|
108
109
|
return text
|
|
109
110
|
.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:
|
|
111
|
+
.replace(/,? or move to a plan that allows it: (?:`promigence billing (?:card|portal)`|Change plan in Billing \(`promigence billing` prints the link\))\.?/, `, or email ${SUPPORT} for a plan that allows it.`)
|
|
111
112
|
.replace(/or add a card to lift it: `promigence billing (?:card|portal)`/, `or email ${SUPPORT} to lift it`)
|
|
113
|
+
.replace(/or lift it by adding a card \(`promigence billing card`\) or buying credits \(`promigence billing buy <usd>`\)/, `or email ${SUPPORT} to lift it`)
|
|
112
114
|
.replace(/adding a card raises it \(owners: `promigence billing (?:card|portal)`\)\.?/, `to raise it, email ${SUPPORT}.`)
|
|
113
|
-
.replace(/Add
|
|
114
|
-
.replace(
|
|
115
|
-
.replace(
|
|
115
|
+
.replace(/Add credits(?: to keep going)? \(owners: `promigence billing buy <usd>`, or Add credits in Billing; members ask an owner\)(?:, or turn on auto-reload)?\./, more)
|
|
116
|
+
.replace(/Add credits to go on \(owners: `promigence billing buy <usd>`; members ask an owner\), then resume it:/, `Payments are not open yet: email ${SUPPORT} for more credits, then resume it:`)
|
|
117
|
+
.replace(/Add credits by hand: `promigence billing buy <usd>`\./, `For more credits, email ${SUPPORT}.`)
|
|
118
|
+
.replace(/ Or add credits: `promigence billing buy <usd>`\./, "")
|
|
119
|
+
.replace(/Add a card(?: to keep going)? \(owners: `promigence billing (?:card|portal)`[^)]*\)\.?/, more)
|
|
120
|
+
.replace(/\(?owners: `promigence billing (?:card|portal|buy <usd>)`(?:; members ask an owner)?\)?/g, `email ${SUPPORT}`)
|
|
121
|
+
.replace(/`promigence billing (?:card|portal|buy <usd>)`/g, SUPPORT);
|
|
116
122
|
}
|
|
117
|
-
export const CREDIT_UNCLAIMED_FIX = "Claim your free credit first: `promigence credits claim` (owners; members ask an owner). Or add
|
|
123
|
+
export const CREDIT_UNCLAIMED_FIX = "Claim your free credit first: `promigence credits claim` (owners; members ask an owner). Or add credits: `promigence billing buy <usd>`.";
|
|
118
124
|
const ANY_HELP = /See `promigence [a-z][a-z -]* --help`\.?$/;
|
|
119
125
|
const API_WORDS = [
|
|
120
126
|
[/`timeout_ms`\s+(\d+)/g, "--timeout", (_m, ms) => `\`--timeout ${duration(Number(ms))}\``],
|
package/dist/generated.js
CHANGED
|
@@ -79,7 +79,7 @@ export const ERRORS = [
|
|
|
79
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
80
|
{ code: "credits_paused", category: "cap", http: 402, exit: 5, billed: "no",
|
|
81
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
|
|
82
|
+
fix: "Its files and state are kept, and paused time is not billed. Add credits to go on (owners: `promigence billing buy <usd>`; members ask an owner), then resume it: `promigence sandbox resume {sandbox_id}`. Or end it: `promigence sandbox kill {sandbox_id}`." },
|
|
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." },
|
|
@@ -175,19 +175,34 @@ export const ERRORS = [
|
|
|
175
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
176
|
{ code: "trial_credits_exhausted", category: "cap", http: 402, exit: 5, billed: "no",
|
|
177
177
|
message: "trial credits left ({remaining}) do not cover this ({needed})",
|
|
178
|
-
fix: "Add
|
|
178
|
+
fix: "Add credits to keep going (owners: `promigence billing buy <usd>`, or Add credits in Billing; members ask an owner). Running sandboxes finish the time they reserved." },
|
|
179
|
+
{ code: "credits_exhausted", category: "cap", http: 402, exit: 5, billed: "no",
|
|
180
|
+
message: "available credits ({remaining}) do not cover this ({needed})",
|
|
181
|
+
fix: "Add credits (owners: `promigence billing buy <usd>`, or Add credits in Billing; members ask an owner), or turn on auto-reload. Running sandboxes finish the time they reserved." },
|
|
179
182
|
{ code: "credit_unclaimed", category: "other", http: 402, exit: 5, billed: "no",
|
|
180
183
|
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
|
|
184
|
+
fix: "Claim it in your browser: `promigence credits claim` (owners; members ask an owner). Or add credits: `promigence billing buy <usd>`. Nothing was started or charged." },
|
|
182
185
|
{ code: "setup_required", category: "other", http: 403, exit: 7, billed: "no",
|
|
183
186
|
message: "finish setting up your account before starting new work",
|
|
184
187
|
fix: "Open {setup_url} and answer the setup questions (under a minute), then run this again. Nothing was started or charged." },
|
|
185
188
|
{ code: "card_required", category: "other", http: 402, exit: 5, billed: "no",
|
|
186
189
|
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
|
|
190
|
+
fix: "Add a card (owners: `promigence billing card`, or POST /v1/billing/checkout; members ask an owner). Your credits are kept, and reads and results stay available." },
|
|
188
191
|
{ code: "billing_unavailable", category: "other", http: 503, exit: 5, billed: "no",
|
|
189
|
-
message: "
|
|
190
|
-
fix: "Nothing was charged. Your
|
|
192
|
+
message: "payments are not available right now",
|
|
193
|
+
fix: "Nothing was charged. Your credits and running work are unaffected. Try again later, or write to support@promigence.ai." },
|
|
194
|
+
{ code: "purchase_limit", category: "other", http: 402, exit: 5, billed: "no",
|
|
195
|
+
message: "{needed} is more than this organization can buy at once right now (up to {limit})",
|
|
196
|
+
fix: "Buy {limit} or less, or choose a smaller plan. The limit rises as the organization's payment history grows; for more now, write to support@promigence.ai." },
|
|
197
|
+
{ code: "card_needed", category: "other", http: 409, exit: 5, billed: "no",
|
|
198
|
+
message: "auto-reload needs a saved card",
|
|
199
|
+
fix: "Add credits once, or add a card in Billing, then turn auto-reload on." },
|
|
200
|
+
{ code: "auto_reload_unavailable", category: "other", http: 409, exit: 5, billed: "no",
|
|
201
|
+
message: "auto-reload isn't available yet for cards issued in India",
|
|
202
|
+
fix: "Add credits by hand: `promigence billing buy <usd>`." },
|
|
203
|
+
{ code: "purchases_blocked", category: "other", http: 409, exit: 5, billed: "no",
|
|
204
|
+
message: "this organization cannot buy credits right now: a payment for this organization is disputed",
|
|
205
|
+
fix: "Write to support@promigence.ai." },
|
|
191
206
|
{ code: "concurrency_limit", category: "other", http: 409, exit: 5, billed: "no",
|
|
192
207
|
message: "{live} live + {requested} requested sandboxes is over your limit of {limit}",
|
|
193
208
|
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." },
|
|
@@ -202,10 +217,10 @@ export const ERRORS = [
|
|
|
202
217
|
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
218
|
{ code: "billing_hold", category: "other", http: 402, exit: 5, billed: "no",
|
|
204
219
|
message: "new work is on hold: {reason}",
|
|
205
|
-
fix: "Running sandboxes finish
|
|
220
|
+
fix: "Running sandboxes finish, and files and results stay available. An owner sees why, and what lifts it, in Billing (`promigence billing` prints the link), or write to support@promigence.ai." },
|
|
206
221
|
{ code: "tier_over_plan", category: "other", http: 403, exit: 2, billed: "no",
|
|
207
222
|
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
|
|
223
|
+
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: Change plan in Billing (`promigence billing` prints the link)." },
|
|
209
224
|
{ code: "network_host_refused", category: "other", http: 403, exit: 9, billed: "no",
|
|
210
225
|
message: "{host} is not on this sandbox's allowed list, so the connection was refused",
|
|
211
226
|
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." },
|
package/dist/guide.js
CHANGED
|
@@ -9,8 +9,8 @@ import { DOCS_URL, EXIT_CODES, EXIT_PRECEDENCE_TEXT, GOLDEN_PATH, GROUPS, GUIDE_
|
|
|
9
9
|
export const SECTIONS = ["core", "commands", "errors", "cost"];
|
|
10
10
|
export const BUDGETS = {
|
|
11
11
|
core: 1500,
|
|
12
|
-
commands:
|
|
13
|
-
errors:
|
|
12
|
+
commands: 4825,
|
|
13
|
+
errors: 2475,
|
|
14
14
|
cost: 600,
|
|
15
15
|
};
|
|
16
16
|
export function lookupError(code) {
|
|
@@ -253,7 +253,9 @@ function renderCost(prices) {
|
|
|
253
253
|
: prices.source === "api"
|
|
254
254
|
? `Live from the API (${view?.as_of ?? "now"}): your organization's prices. \`promigence pricing\` shows the rest.`
|
|
255
255
|
: prices.source === "published"
|
|
256
|
-
?
|
|
256
|
+
? prices.reason !== undefined
|
|
257
|
+
? "Published list prices: the API refused this key. Your organization's own: `promigence login`, then `promigence pricing`."
|
|
258
|
+
: "Published list prices. Your organization's own: `promigence login`, then `promigence pricing`."
|
|
257
259
|
: `${prices.note ?? "list prices at build time; could not reach the API"} (\`promigence pricing\` asks again).`;
|
|
258
260
|
const limit = view?.limits.max_sandbox_vcpus;
|
|
259
261
|
const out = [
|
package/dist/handlers.js
CHANGED
|
@@ -4,7 +4,7 @@ import { BUNDLE_EXT, DEFAULT_SNAPSHOT, PromigenceError, VERSION as SDK_VERSION,
|
|
|
4
4
|
import { storeLabel } from "./sdk/credstore.js";
|
|
5
5
|
import { bool, client, list, nexts, positional, required, str, } from "./commands.js";
|
|
6
6
|
import { emit, exitWith, forkSummary, markGuideSeen, ms, okEnvelope, parseCount, parseDuration, parseUsd, pickExit, usageError, write, } from "./io.js";
|
|
7
|
-
import { ALL_ERROR_CODES, BUDGETS, estimateTokens, guideJson, humanHeader, lookupError, renderGuide } from "./guide.js";
|
|
7
|
+
import { ALL_ERROR_CODES, BUDGETS, estimateTokens, guideJson, humanHeader, lookupError, renderGuide, renderLlmsTxt } from "./guide.js";
|
|
8
8
|
import { livePricing, quickClient } from "./pricing.js";
|
|
9
9
|
import { install, installLines } from "./install.js";
|
|
10
10
|
import { backgroundOutput } from "./live.js";
|
|
@@ -20,6 +20,15 @@ const agentGuide = async (ctx) => {
|
|
|
20
20
|
throw usageError(`--format: '${format}' is not a format`, "Pass --format md (default) or --format json.");
|
|
21
21
|
}
|
|
22
22
|
const json = format === "json";
|
|
23
|
+
if (bool(ctx, "--llms")) {
|
|
24
|
+
const other = ["--section", "--code", "--install", "--check", "--create"].find((f) => ctx.flags.has(f));
|
|
25
|
+
if (other !== undefined || str(ctx, "--format") !== undefined) {
|
|
26
|
+
throw usageError(`--llms takes no other flag (got ${other ?? "--format"})`, "Run promigence agent-guide --llms on its own.");
|
|
27
|
+
}
|
|
28
|
+
markGuideSeen();
|
|
29
|
+
await write(process.stdout, renderLlmsTxt());
|
|
30
|
+
return exitWith(0);
|
|
31
|
+
}
|
|
23
32
|
if (bool(ctx, "--create") && !bool(ctx, "--install") && !bool(ctx, "--check")) {
|
|
24
33
|
throw usageError("--create needs --install", "Pass --install --create to write AGENTS.md (and the skill and rule files) here.");
|
|
25
34
|
}
|